Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell11
提交
b642e31e
D
dragonwell11
项目概览
openanolis
/
dragonwell11
通知
7
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell11
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
b642e31e
编写于
9月 16, 2015
作者:
H
hannesw
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
8134609: Allow constructors with same prototoype map to share the allocator map
Reviewed-by: attila, sundar
上级
92853b17
变更
15
隐藏空白更改
内联
并排
Showing
15 changed file
with
655 addition
and
187 deletion
+655
-187
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
...classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
+3
-3
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AllocationStrategy.java
...sses/jdk/nashorn/internal/runtime/AllocationStrategy.java
+84
-3
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Debug.java
...orn/share/classes/jdk/nashorn/internal/runtime/Debug.java
+11
-0
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyListeners.java
...asses/jdk/nashorn/internal/runtime/PropertyListeners.java
+14
-10
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java
...are/classes/jdk/nashorn/internal/runtime/PropertyMap.java
+170
-119
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
...horn/internal/runtime/RecompilableScriptFunctionData.java
+2
-2
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
.../classes/jdk/nashorn/internal/runtime/ScriptFunction.java
+23
-19
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java
...sses/jdk/nashorn/internal/runtime/ScriptFunctionData.java
+2
-1
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
...re/classes/jdk/nashorn/internal/runtime/ScriptObject.java
+34
-20
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
...lasses/jdk/nashorn/internal/runtime/SetMethodCreator.java
+2
-5
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SharedPropertyMap.java
...asses/jdk/nashorn/internal/runtime/SharedPropertyMap.java
+100
-0
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
...hare/classes/jdk/nashorn/internal/runtime/WithObject.java
+15
-4
nashorn/test/script/basic/JDK-8134569.js
nashorn/test/script/basic/JDK-8134569.js
+80
-1
nashorn/test/script/basic/JDK-8134569.js.EXPECTED
nashorn/test/script/basic/JDK-8134569.js.EXPECTED
+20
-0
nashorn/test/script/basic/JDK-8134609.js
nashorn/test/script/basic/JDK-8134609.js
+95
-0
未找到文件。
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJSAdapter.java
浏览文件 @
b642e31e
...
...
@@ -627,7 +627,7 @@ public final class NativeJSAdapter extends ScriptObject {
return
new
GuardedInvocation
(
MH
.
dropArguments
(
MH
.
constant
(
Object
.
class
,
func
.
createBound
(
this
,
new
Object
[]
{
name
})),
0
,
Object
.
class
),
testJSAdaptor
(
adaptee
,
null
,
null
,
null
),
adaptee
.
getProtoSwitchPoint
(
__call__
,
find
.
getOwner
())
);
adaptee
.
getProtoSwitchPoint
s
(
__call__
,
find
.
getOwner
()),
null
);
}
}
throw
typeError
(
"no.such.function"
,
desc
.
getNameToken
(
2
),
ScriptRuntime
.
safeToString
(
this
));
...
...
@@ -698,7 +698,7 @@ public final class NativeJSAdapter extends ScriptObject {
return
new
GuardedInvocation
(
methodHandle
,
testJSAdaptor
(
adaptee
,
findData
.
getGetter
(
Object
.
class
,
INVALID_PROGRAM_POINT
,
null
),
findData
.
getOwner
(),
func
),
adaptee
.
getProtoSwitchPoint
(
hook
,
findData
.
getOwner
())
);
adaptee
.
getProtoSwitchPoint
s
(
hook
,
findData
.
getOwner
()),
null
);
}
}
}
...
...
@@ -710,7 +710,7 @@ public final class NativeJSAdapter extends ScriptObject {
final
MethodHandle
methodHandle
=
hook
.
equals
(
__put__
)
?
MH
.
asType
(
Lookup
.
EMPTY_SETTER
,
type
)
:
Lookup
.
emptyGetter
(
type
.
returnType
());
return
new
GuardedInvocation
(
methodHandle
,
testJSAdaptor
(
adaptee
,
null
,
null
,
null
),
adaptee
.
getProtoSwitchPoint
(
hook
,
null
)
);
return
new
GuardedInvocation
(
methodHandle
,
testJSAdaptor
(
adaptee
,
null
,
null
,
null
),
adaptee
.
getProtoSwitchPoint
s
(
hook
,
null
),
null
);
}
}
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/AllocationStrategy.java
浏览文件 @
b642e31e
...
...
@@ -29,6 +29,7 @@ import static jdk.nashorn.internal.lookup.Lookup.MH;
import
java.io.Serializable
;
import
java.lang.invoke.MethodHandle
;
import
java.lang.invoke.MethodHandles
;
import
java.lang.ref.WeakReference
;
import
jdk.nashorn.internal.codegen.Compiler
;
import
jdk.nashorn.internal.codegen.CompilerConstants
;
import
jdk.nashorn.internal.codegen.ObjectClassGenerator
;
...
...
@@ -53,6 +54,9 @@ final public class AllocationStrategy implements Serializable {
/** lazily generated allocator */
private
transient
MethodHandle
allocator
;
/** Last used allocator map */
private
transient
AllocatorMap
lastMap
;
/**
* Construct an allocation strategy with the given map and class name.
* @param fieldCount number of fields in the allocated object
...
...
@@ -71,11 +75,49 @@ final public class AllocationStrategy implements Serializable {
return
allocatorClassName
;
}
PropertyMap
getAllocatorMap
()
{
// Create a new map for each function instance
return
PropertyMap
.
newMap
(
null
,
getAllocatorClassName
(),
0
,
fieldCount
,
0
);
/**
* Get the property map for the allocated object.
* @param prototype the prototype object
* @return the property map
*/
synchronized
PropertyMap
getAllocatorMap
(
final
ScriptObject
prototype
)
{
assert
prototype
!=
null
;
final
PropertyMap
protoMap
=
prototype
.
getMap
();
if
(
lastMap
!=
null
)
{
if
(!
lastMap
.
hasSharedProtoMap
())
{
if
(
lastMap
.
hasSamePrototype
(
prototype
))
{
return
lastMap
.
allocatorMap
;
}
if
(
lastMap
.
hasSameProtoMap
(
protoMap
)
&&
lastMap
.
hasUnchangedProtoMap
())
{
// Convert to shared prototype map. Allocated objects will use the same property map
// that can be used as long as none of the prototypes modify the shared proto map.
final
PropertyMap
allocatorMap
=
PropertyMap
.
newMap
(
null
,
getAllocatorClassName
(),
0
,
fieldCount
,
0
);
final
SharedPropertyMap
sharedProtoMap
=
new
SharedPropertyMap
(
protoMap
);
allocatorMap
.
setSharedProtoMap
(
sharedProtoMap
);
prototype
.
setMap
(
sharedProtoMap
);
lastMap
=
new
AllocatorMap
(
prototype
,
protoMap
,
allocatorMap
);
return
allocatorMap
;
}
}
if
(
lastMap
.
hasValidSharedProtoMap
()
&&
lastMap
.
hasSameProtoMap
(
protoMap
))
{
prototype
.
setMap
(
lastMap
.
getSharedProtoMap
());
return
lastMap
.
allocatorMap
;
}
}
final
PropertyMap
allocatorMap
=
PropertyMap
.
newMap
(
null
,
getAllocatorClassName
(),
0
,
fieldCount
,
0
);
lastMap
=
new
AllocatorMap
(
prototype
,
protoMap
,
allocatorMap
);
return
allocatorMap
;
}
/**
* Allocate an object with the given property map
* @param map the property map
* @return the allocated object
*/
ScriptObject
allocate
(
final
PropertyMap
map
)
{
try
{
if
(
allocator
==
null
)
{
...
...
@@ -94,4 +136,43 @@ final public class AllocationStrategy implements Serializable {
public
String
toString
()
{
return
"AllocationStrategy[fieldCount="
+
fieldCount
+
"]"
;
}
static
class
AllocatorMap
{
final
private
WeakReference
<
ScriptObject
>
prototype
;
final
private
WeakReference
<
PropertyMap
>
prototypeMap
;
private
PropertyMap
allocatorMap
;
AllocatorMap
(
final
ScriptObject
prototype
,
final
PropertyMap
protoMap
,
final
PropertyMap
allocMap
)
{
this
.
prototype
=
new
WeakReference
<>(
prototype
);
this
.
prototypeMap
=
new
WeakReference
<>(
protoMap
);
this
.
allocatorMap
=
allocMap
;
}
boolean
hasSamePrototype
(
final
ScriptObject
proto
)
{
return
prototype
.
get
()
==
proto
;
}
boolean
hasSameProtoMap
(
final
PropertyMap
protoMap
)
{
return
prototypeMap
.
get
()
==
protoMap
||
allocatorMap
.
getSharedProtoMap
()
==
protoMap
;
}
boolean
hasUnchangedProtoMap
()
{
final
ScriptObject
proto
=
prototype
.
get
();
return
proto
!=
null
&&
proto
.
getMap
()
==
prototypeMap
.
get
();
}
boolean
hasSharedProtoMap
()
{
return
getSharedProtoMap
()
!=
null
;
}
boolean
hasValidSharedProtoMap
()
{
return
hasSharedProtoMap
()
&&
getSharedProtoMap
().
isValidSharedProtoMap
();
}
PropertyMap
getSharedProtoMap
()
{
return
allocatorMap
.
getSharedProtoMap
();
}
}
}
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Debug.java
浏览文件 @
b642e31e
...
...
@@ -26,6 +26,8 @@
package
jdk.nashorn.internal.runtime
;
import
static
jdk
.
nashorn
.
internal
.
parser
.
TokenType
.
EOF
;
import
jdk.nashorn.api.scripting.NashornException
;
import
jdk.nashorn.internal.parser.Lexer
;
import
jdk.nashorn.internal.parser.Token
;
import
jdk.nashorn.internal.parser.TokenStream
;
...
...
@@ -62,6 +64,15 @@ public final class Debug {
return
firstJSFrame
(
new
Throwable
());
}
/**
* Return a formatted script stack trace string with frames information separated by '\n'.
* This is a shortcut for {@code NashornException.getScriptStackString(new Throwable())}.
* @return formatted stack trace string
*/
public
static
String
scriptStack
()
{
return
NashornException
.
getScriptStackString
(
new
Throwable
());
}
/**
* Return the system identity hashcode for an object as a human readable
* string
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyListeners.java
浏览文件 @
b642e31e
...
...
@@ -75,16 +75,20 @@ public class PropertyListeners {
}
/**
* Return
listeners added to this
ScriptObject.
* Return
number of listeners added to a
ScriptObject.
* @param obj the object
* @return the listener count
*/
public
static
int
getListenerCount
(
final
ScriptObject
obj
)
{
final
PropertyListeners
propertyListeners
=
obj
.
getMap
().
getListeners
();
if
(
propertyListeners
!=
null
)
{
return
propertyListeners
.
listeners
==
null
?
0
:
propertyListeners
.
listeners
.
size
();
}
return
0
;
return
obj
.
getMap
().
getListenerCount
();
}
/**
* Return the number of listeners added to this PropertyListeners instance.
* @return the listener count;
*/
public
int
getListenerCount
()
{
return
listeners
==
null
?
0
:
listeners
.
size
();
}
// Property listener management methods
...
...
@@ -156,7 +160,7 @@ public class PropertyListeners {
final
WeakPropertyMapSet
set
=
listeners
.
get
(
prop
.
getKey
());
if
(
set
!=
null
)
{
for
(
final
PropertyMap
propertyMap
:
set
.
elements
())
{
propertyMap
.
propertyAdded
(
prop
);
propertyMap
.
propertyAdded
(
prop
,
false
);
}
listeners
.
remove
(
prop
.
getKey
());
if
(
Context
.
DEBUG
)
{
...
...
@@ -176,7 +180,7 @@ public class PropertyListeners {
final
WeakPropertyMapSet
set
=
listeners
.
get
(
prop
.
getKey
());
if
(
set
!=
null
)
{
for
(
final
PropertyMap
propertyMap
:
set
.
elements
())
{
propertyMap
.
propertyDeleted
(
prop
);
propertyMap
.
propertyDeleted
(
prop
,
false
);
}
listeners
.
remove
(
prop
.
getKey
());
if
(
Context
.
DEBUG
)
{
...
...
@@ -198,7 +202,7 @@ public class PropertyListeners {
final
WeakPropertyMapSet
set
=
listeners
.
get
(
oldProp
.
getKey
());
if
(
set
!=
null
)
{
for
(
final
PropertyMap
propertyMap
:
set
.
elements
())
{
propertyMap
.
propertyModified
(
oldProp
,
newProp
);
propertyMap
.
propertyModified
(
oldProp
,
newProp
,
false
);
}
listeners
.
remove
(
oldProp
.
getKey
());
if
(
Context
.
DEBUG
)
{
...
...
@@ -215,7 +219,7 @@ public class PropertyListeners {
if
(
listeners
!=
null
)
{
for
(
final
WeakPropertyMapSet
set
:
listeners
.
values
())
{
for
(
final
PropertyMap
propertyMap
:
set
.
elements
())
{
propertyMap
.
protoChanged
();
propertyMap
.
protoChanged
(
false
);
}
}
listeners
.
clear
();
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/PropertyMap.java
浏览文件 @
b642e31e
...
...
@@ -54,32 +54,36 @@ import jdk.nashorn.internal.scripts.JO;
* All property maps are immutable. If a property is added, modified or removed, the mutator
* will return a new map.
*/
public
final
class
PropertyMap
implements
Iterable
<
Object
>,
Serializable
{
public
class
PropertyMap
implements
Iterable
<
Object
>,
Serializable
{
/** Used for non extensible PropertyMaps, negative logic as the normal case is extensible. See {@link ScriptObject#preventExtensions()} */
p
ublic
static
final
int
NOT_EXTENSIBLE
=
0b0000_0001
;
p
rivate
static
final
int
NOT_EXTENSIBLE
=
0b0000_0001
;
/** Does this map contain valid array keys? */
p
ublic
static
final
int
CONTAINS_ARRAY_KEYS
=
0b0000_0010
;
p
rivate
static
final
int
CONTAINS_ARRAY_KEYS
=
0b0000_0010
;
/** Map status flags. */
private
int
flags
;
private
final
int
flags
;
/** Map of properties. */
private
transient
PropertyHashMap
properties
;
/** Number of fields in use. */
private
int
fieldCount
;
private
final
int
fieldCount
;
/** Number of fields available. */
private
final
int
fieldMaximum
;
/** Length of spill in use. */
private
int
spillLength
;
private
final
int
spillLength
;
/** Structure class name */
private
String
className
;
private
final
String
className
;
/** A reference to the expected shared prototype property map. If this is set this
* property map should only be used if it the same as the actual prototype map. */
private
transient
SharedPropertyMap
sharedProtoMap
;
/** {@link SwitchPoint}s for gets on inherited properties. */
private
transient
HashMap
<
String
,
SwitchPoint
>
proto
Get
Switches
;
private
transient
HashMap
<
String
,
SwitchPoint
>
protoSwitches
;
/** History of maps, used to limit map duplication. */
private
transient
WeakHashMap
<
Property
,
SoftReference
<
PropertyMap
>>
history
;
...
...
@@ -95,24 +99,21 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
private
static
final
long
serialVersionUID
=
-
7041836752008732533L
;
/**
* Construct
or
.
* Construct
s a new property map
.
*
* @param properties A {@link PropertyHashMap} with initial contents.
* @param fieldCount Number of fields in use.
* @param fieldMaximum Number of fields available.
* @param spillLength Number of spill slots used.
* @param containsArrayKeys True if properties contain numeric keys
*/
private
PropertyMap
(
final
PropertyHashMap
properties
,
final
String
className
,
final
int
fieldCount
,
final
int
field
Maximum
,
final
int
spillLength
,
final
boolean
containsArrayKeys
)
{
private
PropertyMap
(
final
PropertyHashMap
properties
,
final
int
flags
,
final
String
className
,
final
int
field
Count
,
final
int
fieldMaximum
,
final
int
spillLength
)
{
this
.
properties
=
properties
;
this
.
className
=
className
;
this
.
fieldCount
=
fieldCount
;
this
.
fieldMaximum
=
fieldMaximum
;
this
.
spillLength
=
spillLength
;
if
(
containsArrayKeys
)
{
setContainsArrayKeys
();
}
this
.
flags
=
flags
;
if
(
Context
.
DEBUG
)
{
count
.
increment
();
...
...
@@ -120,20 +121,22 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
}
/**
* C
loning constructor
.
* C
onstructs a clone of {@code propertyMap} with changed properties, flags, or boundaries
.
*
* @param propertyMap Existing property map.
* @param properties A {@link PropertyHashMap} with a new set of properties.
*/
private
PropertyMap
(
final
PropertyMap
propertyMap
,
final
PropertyHashMap
properties
)
{
private
PropertyMap
(
final
PropertyMap
propertyMap
,
final
PropertyHashMap
properties
,
final
int
flags
,
final
int
fieldCount
,
final
int
spillLength
)
{
this
.
properties
=
properties
;
this
.
flags
=
propertyMap
.
flags
;
this
.
spillLength
=
propertyMap
.
spillLength
;
this
.
fieldCount
=
propertyMap
.
fieldCount
;
this
.
flags
=
flags
;
this
.
spillLength
=
spillLength
;
this
.
fieldCount
=
fieldCount
;
this
.
fieldMaximum
=
propertyMap
.
fieldMaximum
;
this
.
className
=
propertyMap
.
className
;
// We inherit the parent property listeners instance. It will be cloned when a new listener is added.
this
.
listeners
=
propertyMap
.
listeners
;
this
.
freeSlots
=
propertyMap
.
freeSlots
;
this
.
sharedProtoMap
=
propertyMap
.
sharedProtoMap
;
if
(
Context
.
DEBUG
)
{
count
.
increment
();
...
...
@@ -142,12 +145,12 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
}
/**
* C
loning constructor
.
* C
onstructs an exact clone of {@code propertyMap}
.
*
* @param propertyMap Existing property map.
*/
pr
ivate
PropertyMap
(
final
PropertyMap
propertyMap
)
{
this
(
propertyMap
,
propertyMap
.
properties
);
pr
otected
PropertyMap
(
final
PropertyMap
propertyMap
)
{
this
(
propertyMap
,
propertyMap
.
properties
,
propertyMap
.
flags
,
propertyMap
.
fieldCount
,
propertyMap
.
spillLength
);
}
private
void
writeObject
(
final
ObjectOutputStream
out
)
throws
IOException
{
...
...
@@ -183,7 +186,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*/
public
static
PropertyMap
newMap
(
final
Collection
<
Property
>
properties
,
final
String
className
,
final
int
fieldCount
,
final
int
fieldMaximum
,
final
int
spillLength
)
{
final
PropertyHashMap
newProperties
=
EMPTY_HASHMAP
.
immutableAdd
(
properties
);
return
new
PropertyMap
(
newProperties
,
className
,
fieldCount
,
fieldMaximum
,
spillLength
,
false
);
return
new
PropertyMap
(
newProperties
,
0
,
className
,
fieldCount
,
fieldMaximum
,
spillLength
);
}
/**
...
...
@@ -205,7 +208,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
* @return New empty {@link PropertyMap}.
*/
public
static
PropertyMap
newMap
(
final
Class
<?
extends
ScriptObject
>
clazz
)
{
return
new
PropertyMap
(
EMPTY_HASHMAP
,
clazz
.
getName
(),
0
,
0
,
0
,
false
);
return
new
PropertyMap
(
EMPTY_HASHMAP
,
0
,
clazz
.
getName
(),
0
,
0
,
0
);
}
/**
...
...
@@ -227,12 +230,12 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
}
/**
* Get the
listeners of this map, or null if none exists
* Get the
number of listeners of this map
*
* @return the listeners
* @return the
number of
listeners
*/
public
PropertyListeners
getListeners
()
{
return
listeners
;
public
int
getListenerCount
()
{
return
listeners
==
null
?
0
:
listeners
.
getListenerCount
()
;
}
/**
...
...
@@ -253,9 +256,12 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
* A new property is being added.
*
* @param property The new Property added.
* @param isSelf was the property added to this map?
*/
public
void
propertyAdded
(
final
Property
property
)
{
invalidateProtoGetSwitchPoint
(
property
);
public
void
propertyAdded
(
final
Property
property
,
final
boolean
isSelf
)
{
if
(!
isSelf
)
{
invalidateProtoSwitchPoint
(
property
.
getKey
());
}
if
(
listeners
!=
null
)
{
listeners
.
propertyAdded
(
property
);
}
...
...
@@ -265,9 +271,12 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
* An existing property is being deleted.
*
* @param property The property being deleted.
* @param isSelf was the property deleted from this map?
*/
public
void
propertyDeleted
(
final
Property
property
)
{
invalidateProtoGetSwitchPoint
(
property
);
public
void
propertyDeleted
(
final
Property
property
,
final
boolean
isSelf
)
{
if
(!
isSelf
)
{
invalidateProtoSwitchPoint
(
property
.
getKey
());
}
if
(
listeners
!=
null
)
{
listeners
.
propertyDeleted
(
property
);
}
...
...
@@ -278,9 +287,12 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*
* @param oldProperty The old property
* @param newProperty The new property
* @param isSelf was the property modified on this map?
*/
public
void
propertyModified
(
final
Property
oldProperty
,
final
Property
newProperty
)
{
invalidateProtoGetSwitchPoint
(
oldProperty
);
public
void
propertyModified
(
final
Property
oldProperty
,
final
Property
newProperty
,
final
boolean
isSelf
)
{
if
(!
isSelf
)
{
invalidateProtoSwitchPoint
(
oldProperty
.
getKey
());
}
if
(
listeners
!=
null
)
{
listeners
.
propertyModified
(
oldProperty
,
newProperty
);
}
...
...
@@ -288,9 +300,15 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
/**
* The prototype of an object associated with this {@link PropertyMap} is changed.
*
* @param isSelf was the prototype changed on the object using this map?
*/
public
void
protoChanged
()
{
invalidateAllProtoGetSwitchPoints
();
public
void
protoChanged
(
final
boolean
isSelf
)
{
if
(!
isSelf
)
{
invalidateAllProtoSwitchPoints
();
}
else
if
(
sharedProtoMap
!=
null
)
{
sharedProtoMap
.
invalidateSwitchPoint
();
}
if
(
listeners
!=
null
)
{
listeners
.
protoChanged
();
}
...
...
@@ -303,14 +321,14 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
* @return A shared {@link SwitchPoint} for the property.
*/
public
synchronized
SwitchPoint
getSwitchPoint
(
final
String
key
)
{
if
(
proto
Get
Switches
==
null
)
{
proto
Get
Switches
=
new
HashMap
<>();
if
(
protoSwitches
==
null
)
{
protoSwitches
=
new
HashMap
<>();
}
SwitchPoint
switchPoint
=
proto
Get
Switches
.
get
(
key
);
SwitchPoint
switchPoint
=
protoSwitches
.
get
(
key
);
if
(
switchPoint
==
null
)
{
switchPoint
=
new
SwitchPoint
();
proto
Get
Switches
.
put
(
key
,
switchPoint
);
protoSwitches
.
put
(
key
,
switchPoint
);
}
return
switchPoint
;
...
...
@@ -319,19 +337,17 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
/**
* Indicate that a prototype property has changed.
*
* @param
property {@link Property}
to invalidate.
* @param
key {@link Property} key
to invalidate.
*/
synchronized
void
invalidateProtoGetSwitchPoint
(
final
Property
property
)
{
if
(
protoGetSwitches
!=
null
)
{
final
String
key
=
property
.
getKey
();
final
SwitchPoint
sp
=
protoGetSwitches
.
get
(
key
);
synchronized
void
invalidateProtoSwitchPoint
(
final
String
key
)
{
if
(
protoSwitches
!=
null
)
{
final
SwitchPoint
sp
=
protoSwitches
.
get
(
key
);
if
(
sp
!=
null
)
{
proto
Get
Switches
.
remove
(
key
);
protoSwitches
.
remove
(
key
);
if
(
Context
.
DEBUG
)
{
protoInvalidations
.
increment
();
}
SwitchPoint
.
invalidateAll
(
new
SwitchPoint
[]
{
sp
});
SwitchPoint
.
invalidateAll
(
new
SwitchPoint
[]
{
sp
});
}
}
}
...
...
@@ -339,15 +355,15 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
/**
* Indicate that proto itself has changed in hierarchy somewhere.
*/
synchronized
void
invalidateAllProto
Get
SwitchPoints
()
{
if
(
proto
Get
Switches
!=
null
)
{
final
int
size
=
proto
Get
Switches
.
size
();
synchronized
void
invalidateAllProtoSwitchPoints
()
{
if
(
protoSwitches
!=
null
)
{
final
int
size
=
protoSwitches
.
size
();
if
(
size
>
0
)
{
if
(
Context
.
DEBUG
)
{
protoInvalidations
.
add
(
size
);
}
SwitchPoint
.
invalidateAll
(
proto
Get
Switches
.
values
().
toArray
(
new
SwitchPoint
[
size
]));
proto
Get
Switches
.
clear
();
SwitchPoint
.
invalidateAll
(
protoSwitches
.
values
().
toArray
(
new
SwitchPoint
[
size
]));
protoSwitches
.
clear
();
}
}
}
...
...
@@ -363,7 +379,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
* @return New {@link PropertyMap} with {@link Property} added.
*/
PropertyMap
addPropertyBind
(
final
AccessorProperty
property
,
final
Object
bindTo
)
{
//
No need to
store bound property in the history as bound properties can't be reused.
//
We must not
store bound property in the history as bound properties can't be reused.
return
addPropertyNoHistory
(
new
AccessorProperty
(
property
,
bindTo
));
}
...
...
@@ -376,16 +392,16 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
return
property
.
isSpill
()
?
slot
+
fieldMaximum
:
slot
;
}
// Update boundaries and flags after a property has been added
private
void
updateFlagsAndBoundaries
(
final
Property
newProperty
)
{
if
(
newProperty
.
isSpill
())
{
spillLength
=
Math
.
max
(
spillLength
,
newProperty
.
getSlot
()
+
1
);
}
else
{
fieldCount
=
Math
.
max
(
fieldCount
,
newProperty
.
getSlot
()
+
1
)
;
}
if
(
isValidArrayIndex
(
getArrayIndex
(
newProperty
.
getKey
())))
{
setContainsArrayKeys
();
}
private
int
newSpillLength
(
final
Property
newProperty
)
{
return
newProperty
.
isSpill
()
?
Math
.
max
(
spillLength
,
newProperty
.
getSlot
()
+
1
)
:
spillLength
;
}
private
int
newFieldCount
(
final
Property
newProperty
)
{
return
!
newProperty
.
isSpill
()
?
Math
.
max
(
fieldCount
,
newProperty
.
getSlot
()
+
1
)
:
fieldCount
;
}
private
int
newFlags
(
final
Property
newProperty
)
{
return
isValidArrayIndex
(
getArrayIndex
(
newProperty
.
getKey
()))
?
flags
|
CONTAINS_ARRAY_KEYS
:
flags
;
}
// Update the free slots bitmap for a property that has been deleted and/or added. This method is not synchronized
...
...
@@ -420,13 +436,10 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
* @param property {@link Property} being added.
* @return New {@link PropertyMap} with {@link Property} added.
*/
public
PropertyMap
addPropertyNoHistory
(
final
Property
property
)
{
if
(
listeners
!=
null
)
{
listeners
.
propertyAdded
(
property
);
}
public
final
PropertyMap
addPropertyNoHistory
(
final
Property
property
)
{
propertyAdded
(
property
,
true
);
final
PropertyHashMap
newProperties
=
properties
.
immutableAdd
(
property
);
final
PropertyMap
newMap
=
new
PropertyMap
(
this
,
newProperties
);
newMap
.
updateFlagsAndBoundaries
(
property
);
final
PropertyMap
newMap
=
new
PropertyMap
(
this
,
newProperties
,
newFlags
(
property
),
newFieldCount
(
property
),
newSpillLength
(
property
));
newMap
.
updateFreeSlots
(
null
,
property
);
return
newMap
;
...
...
@@ -439,16 +452,13 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*
* @return New {@link PropertyMap} with {@link Property} added.
*/
public
synchronized
PropertyMap
addProperty
(
final
Property
property
)
{
if
(
listeners
!=
null
)
{
listeners
.
propertyAdded
(
property
);
}
public
final
synchronized
PropertyMap
addProperty
(
final
Property
property
)
{
propertyAdded
(
property
,
true
);
PropertyMap
newMap
=
checkHistory
(
property
);
if
(
newMap
==
null
)
{
final
PropertyHashMap
newProperties
=
properties
.
immutableAdd
(
property
);
newMap
=
new
PropertyMap
(
this
,
newProperties
);
newMap
.
updateFlagsAndBoundaries
(
property
);
newMap
=
new
PropertyMap
(
this
,
newProperties
,
newFlags
(
property
),
newFieldCount
(
property
),
newSpillLength
(
property
));
newMap
.
updateFreeSlots
(
null
,
property
);
addToHistory
(
property
,
newMap
);
}
...
...
@@ -463,10 +473,8 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*
* @return New {@link PropertyMap} with {@link Property} removed or {@code null} if not found.
*/
public
synchronized
PropertyMap
deleteProperty
(
final
Property
property
)
{
if
(
listeners
!=
null
)
{
listeners
.
propertyDeleted
(
property
);
}
public
final
synchronized
PropertyMap
deleteProperty
(
final
Property
property
)
{
propertyDeleted
(
property
,
true
);
PropertyMap
newMap
=
checkHistory
(
property
);
final
String
key
=
property
.
getKey
();
...
...
@@ -477,13 +485,13 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
// If deleted property was last field or spill slot we can make it reusable by reducing field/slot count.
// Otherwise mark it as free in free slots bitset.
if
(
isSpill
&&
slot
>=
0
&&
slot
==
spillLength
-
1
)
{
newMap
=
new
PropertyMap
(
newProperties
,
className
,
fieldCount
,
fieldMaximum
,
spillLength
-
1
,
containsArrayKeys
()
);
newMap
=
new
PropertyMap
(
this
,
newProperties
,
flags
,
fieldCount
,
spillLength
-
1
);
newMap
.
freeSlots
=
freeSlots
;
}
else
if
(!
isSpill
&&
slot
>=
0
&&
slot
==
fieldCount
-
1
)
{
newMap
=
new
PropertyMap
(
newProperties
,
className
,
fieldCount
-
1
,
fieldMaximum
,
spillLength
,
containsArrayKeys
()
);
newMap
=
new
PropertyMap
(
this
,
newProperties
,
flags
,
fieldCount
-
1
,
spillLength
);
newMap
.
freeSlots
=
freeSlots
;
}
else
{
newMap
=
new
PropertyMap
(
this
,
newProperties
);
newMap
=
new
PropertyMap
(
this
,
newProperties
,
flags
,
fieldCount
,
spillLength
);
newMap
.
updateFreeSlots
(
property
,
null
);
}
addToHistory
(
property
,
newMap
);
...
...
@@ -500,13 +508,8 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*
* @return New {@link PropertyMap} with {@link Property} replaced.
*/
public
PropertyMap
replaceProperty
(
final
Property
oldProperty
,
final
Property
newProperty
)
{
if
(
listeners
!=
null
)
{
listeners
.
propertyModified
(
oldProperty
,
newProperty
);
}
// Add replaces existing property.
final
PropertyHashMap
newProperties
=
properties
.
immutableReplace
(
oldProperty
,
newProperty
);
final
PropertyMap
newMap
=
new
PropertyMap
(
this
,
newProperties
);
public
final
PropertyMap
replaceProperty
(
final
Property
oldProperty
,
final
Property
newProperty
)
{
propertyModified
(
oldProperty
,
newProperty
,
true
);
/*
* See ScriptObject.modifyProperty and ScriptObject.setUserAccessors methods.
*
...
...
@@ -528,14 +531,17 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
newProperty
instanceof
UserAccessorProperty
:
"arbitrary replaceProperty attempted "
+
sameType
+
" oldProperty="
+
oldProperty
.
getClass
()
+
" newProperty="
+
newProperty
.
getClass
()
+
" ["
+
oldProperty
.
getLocalType
()
+
" => "
+
newProperty
.
getLocalType
()
+
"]"
;
newMap
.
flags
=
flags
;
/*
* spillLength remains same in case (1) and (2) because of slot reuse. Only for case (3), we need
* to add spill count of the newly added UserAccessorProperty property.
*/
final
int
newSpillLength
=
sameType
?
spillLength
:
Math
.
max
(
spillLength
,
newProperty
.
getSlot
()
+
1
);
// Add replaces existing property.
final
PropertyHashMap
newProperties
=
properties
.
immutableReplace
(
oldProperty
,
newProperty
);
final
PropertyMap
newMap
=
new
PropertyMap
(
this
,
newProperties
,
flags
,
fieldCount
,
newSpillLength
);
if
(!
sameType
)
{
newMap
.
spillLength
=
Math
.
max
(
spillLength
,
newProperty
.
getSlot
()
+
1
);
newMap
.
updateFreeSlots
(
oldProperty
,
newProperty
);
}
return
newMap
;
...
...
@@ -551,7 +557,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
* @param propertyFlags attribute flags of the property
* @return the newly created UserAccessorProperty
*/
public
UserAccessorProperty
newUserAccessors
(
final
String
key
,
final
int
propertyFlags
)
{
public
final
UserAccessorProperty
newUserAccessors
(
final
String
key
,
final
int
propertyFlags
)
{
return
new
UserAccessorProperty
(
key
,
propertyFlags
,
getFreeSpillSlot
());
}
...
...
@@ -562,7 +568,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*
* @return {@link Property} matching key.
*/
public
Property
findProperty
(
final
String
key
)
{
public
final
Property
findProperty
(
final
String
key
)
{
return
properties
.
find
(
key
);
}
...
...
@@ -573,12 +579,12 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*
* @return New {@link PropertyMap} with added properties.
*/
public
PropertyMap
addAll
(
final
PropertyMap
other
)
{
public
final
PropertyMap
addAll
(
final
PropertyMap
other
)
{
assert
this
!=
other
:
"adding property map to itself"
;
final
Property
[]
otherProperties
=
other
.
properties
.
getProperties
();
final
PropertyHashMap
newProperties
=
properties
.
immutableAdd
(
otherProperties
);
final
PropertyMap
newMap
=
new
PropertyMap
(
this
,
newProperties
);
final
PropertyMap
newMap
=
new
PropertyMap
(
this
,
newProperties
,
flags
,
fieldCount
,
spillLength
);
for
(
final
Property
property
:
otherProperties
)
{
// This method is only safe to use with non-slotted, native getter/setter properties
assert
property
.
getSlot
()
==
-
1
;
...
...
@@ -593,7 +599,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*
* @return Properties as an array.
*/
public
Property
[]
getProperties
()
{
public
final
Property
[]
getProperties
()
{
return
properties
.
getProperties
();
}
...
...
@@ -602,7 +608,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
*
* @return class name of owner objects.
*/
public
String
getClassName
()
{
public
final
String
getClassName
()
{
return
className
;
}
...
...
@@ -612,9 +618,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
* @return New map with {@link #NOT_EXTENSIBLE} flag set.
*/
PropertyMap
preventExtensions
()
{
final
PropertyMap
newMap
=
new
PropertyMap
(
this
);
newMap
.
flags
|=
NOT_EXTENSIBLE
;
return
newMap
;
return
new
PropertyMap
(
this
,
properties
,
flags
|
NOT_EXTENSIBLE
,
fieldCount
,
spillLength
);
}
/**
...
...
@@ -630,10 +634,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
newProperties
=
newProperties
.
immutableAdd
(
oldProperty
.
addFlags
(
Property
.
NOT_CONFIGURABLE
));
}
final
PropertyMap
newMap
=
new
PropertyMap
(
this
,
newProperties
);
newMap
.
flags
|=
NOT_EXTENSIBLE
;
return
newMap
;
return
new
PropertyMap
(
this
,
newProperties
,
flags
|
NOT_EXTENSIBLE
,
fieldCount
,
spillLength
);
}
/**
...
...
@@ -655,10 +656,7 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
newProperties
=
newProperties
.
immutableAdd
(
oldProperty
.
addFlags
(
propertyFlags
));
}
final
PropertyMap
newMap
=
new
PropertyMap
(
this
,
newProperties
);
newMap
.
flags
|=
NOT_EXTENSIBLE
;
return
newMap
;
return
new
PropertyMap
(
this
,
newProperties
,
flags
|
NOT_EXTENSIBLE
,
fieldCount
,
spillLength
);
}
/**
...
...
@@ -829,13 +827,6 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
return
(
flags
&
CONTAINS_ARRAY_KEYS
)
!=
0
;
}
/**
* Flag this object as having array keys in defined properties
*/
private
void
setContainsArrayKeys
()
{
flags
|=
CONTAINS_ARRAY_KEYS
;
}
/**
* Test to see if {@link PropertyMap} is extensible.
*
...
...
@@ -914,12 +905,72 @@ public final class PropertyMap implements Iterable<Object>, Serializable {
setProtoNewMapCount
.
increment
();
}
final
PropertyMap
newMap
=
new
PropertyMap
(
this
);
final
PropertyMap
newMap
=
makeUnsharedCopy
(
);
addToProtoHistory
(
newProto
,
newMap
);
return
newMap
;
}
/**
* Make a copy of this property map with the shared prototype field set to null. Note that this is
* only necessary for shared maps of top-level objects. Shared prototype maps represented by
* {@link SharedPropertyMap} are automatically converted to plain property maps when they evolve.
*
* @return a copy with the shared proto map unset
*/
PropertyMap
makeUnsharedCopy
()
{
final
PropertyMap
newMap
=
new
PropertyMap
(
this
);
newMap
.
sharedProtoMap
=
null
;
return
newMap
;
}
/**
* Set a reference to the expected parent prototype map. This is used for class-like
* structures where we only want to use a top-level property map if all of the
* prototype property maps have not been modified.
*
* @param protoMap weak reference to the prototype property map
*/
void
setSharedProtoMap
(
final
SharedPropertyMap
protoMap
)
{
sharedProtoMap
=
protoMap
;
}
/**
* Get the expected prototype property map if it is known, or null.
*
* @return parent map or null
*/
public
PropertyMap
getSharedProtoMap
()
{
return
sharedProtoMap
;
}
/**
* Returns {@code true} if this map has been used as a shared prototype map (i.e. as a prototype
* for a JavaScript constructor function) and has not had properties added, deleted or replaced since then.
* @return true if this is a valid shared prototype map
*/
boolean
isValidSharedProtoMap
()
{
return
false
;
}
/**
* Returns the shared prototype switch point, or null if this is not a shared prototype map.
* @return the shared prototype switch point, or null
*/
SwitchPoint
getSharedProtoSwitchPoint
()
{
return
null
;
}
/**
* Return true if this map has a shared prototype map which has either been invalidated or does
* not match the map of {@code proto}.
* @param prototype the prototype object
* @return true if this is an invalid shared map for {@code prototype}
*/
boolean
isInvalidSharedMapFor
(
final
ScriptObject
prototype
)
{
return
sharedProtoMap
!=
null
&&
(!
sharedProtoMap
.
isValidSharedProtoMap
()
||
prototype
==
null
||
sharedProtoMap
!=
prototype
.
getMap
());
}
/**
* {@link PropertyMap} iterator.
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/RecompilableScriptFunctionData.java
浏览文件 @
b642e31e
...
...
@@ -368,8 +368,8 @@ public final class RecompilableScriptFunctionData extends ScriptFunctionData imp
}
@Override
PropertyMap
getAllocatorMap
()
{
return
allocationStrategy
.
getAllocatorMap
();
PropertyMap
getAllocatorMap
(
final
ScriptObject
prototype
)
{
return
allocationStrategy
.
getAllocatorMap
(
prototype
);
}
@Override
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunction.java
浏览文件 @
b642e31e
...
...
@@ -521,35 +521,39 @@ public class ScriptFunction extends ScriptObject {
assert
!
isBoundFunction
();
// allocate never invoked on bound functions
final
ScriptObject
object
=
data
.
allocate
(
getAllocatorMap
());
final
ScriptObject
prototype
=
getAllocatorPrototype
();
final
ScriptObject
object
=
data
.
allocate
(
getAllocatorMap
(
prototype
));
if
(
object
!=
null
)
{
final
Object
prototype
=
getPrototype
();
if
(
prototype
instanceof
ScriptObject
)
{
object
.
setInitialProto
((
ScriptObject
)
prototype
);
}
if
(
object
.
getProto
()
==
null
)
{
object
.
setInitialProto
(
getObjectPrototype
());
}
object
.
setInitialProto
(
prototype
);
}
return
object
;
}
private
PropertyMap
getAllocatorMap
()
{
if
(
allocatorMap
==
null
)
{
allocatorMap
=
data
.
getAllocatorMap
();
/**
* Get the property map used by "allocate"
* @param prototype actual prototype object
* @return property map
*/
private
synchronized
PropertyMap
getAllocatorMap
(
final
ScriptObject
prototype
)
{
if
(
allocatorMap
==
null
||
allocatorMap
.
isInvalidSharedMapFor
(
prototype
))
{
// The prototype map has changed since this function was last used as constructor.
// Get a new allocator map.
allocatorMap
=
data
.
getAllocatorMap
(
prototype
);
}
return
allocatorMap
;
}
/**
* Return Object.prototype - used by "allocate"
*
* @return Object.prototype
* Return the actual prototype used by "allocate"
* @return allocator prototype
*/
protected
final
ScriptObject
getObjectPrototype
()
{
private
ScriptObject
getAllocatorPrototype
()
{
final
Object
prototype
=
getPrototype
();
if
(
prototype
instanceof
ScriptObject
)
{
return
(
ScriptObject
)
prototype
;
}
return
Global
.
objectPrototype
();
}
...
...
@@ -591,10 +595,10 @@ public class ScriptFunction extends ScriptObject {
*
* @param newPrototype new prototype object
*/
public
final
void
setPrototype
(
final
Object
newPrototype
)
{
public
synchronized
final
void
setPrototype
(
final
Object
newPrototype
)
{
if
(
newPrototype
instanceof
ScriptObject
&&
newPrototype
!=
this
.
prototype
&&
allocatorMap
!=
null
)
{
//
Replace our current allocator map with one that is associated with
the new prototype.
allocatorMap
=
allocatorMap
.
changeProto
((
ScriptObject
)
newPrototype
)
;
//
Unset allocator map to be replaced with one matching
the new prototype.
allocatorMap
=
null
;
}
this
.
prototype
=
newPrototype
;
}
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptFunctionData.java
浏览文件 @
b642e31e
...
...
@@ -389,9 +389,10 @@ public abstract class ScriptFunctionData implements Serializable {
/**
* Get the property map to use for objects allocated by this function.
*
* @param prototype the prototype of the allocated object
* @return the property map for allocated objects.
*/
PropertyMap
getAllocatorMap
()
{
PropertyMap
getAllocatorMap
(
final
ScriptObject
prototype
)
{
return
null
;
}
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/ScriptObject.java
浏览文件 @
b642e31e
...
...
@@ -809,9 +809,11 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
if
(
deep
)
{
final
ScriptObject
myProto
=
getProto
();
if
(
myProto
!=
null
)
{
return
myProto
.
findProperty
(
key
,
deep
,
start
);
}
final
FindProperty
find
=
myProto
==
null
?
null
:
myProto
.
findProperty
(
key
,
true
,
start
);
// checkSharedProtoMap must be invoked after myProto.checkSharedProtoMap to propagate
// shared proto invalidation up the prototype chain. It also must be invoked when prototype is null.
checkSharedProtoMap
();
return
find
;
}
return
null
;
...
...
@@ -832,7 +834,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
if
(
deep
)
{
final
ScriptObject
myProto
=
getProto
();
if
(
myProto
!=
null
)
{
return
myProto
.
hasProperty
(
key
,
deep
);
return
myProto
.
hasProperty
(
key
,
true
);
}
}
...
...
@@ -1258,11 +1260,8 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
if
(
oldProto
!=
newProto
)
{
proto
=
newProto
;
// Let current listeners know that the prototype has changed and set our map
final
PropertyListeners
listeners
=
getMap
().
getListeners
();
if
(
listeners
!=
null
)
{
listeners
.
protoChanged
();
}
// Let current listeners know that the prototype has changed
getMap
().
protoChanged
(
true
);
// Replace our current allocator map with one that is associated with the new prototype.
setMap
(
getMap
().
changeProto
(
newProto
));
}
...
...
@@ -1314,7 +1313,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
}
p
=
p
.
getProto
();
}
setProto
((
ScriptObject
)
newProto
);
setProto
((
ScriptObject
)
newProto
);
}
else
{
throw
typeError
(
"cant.set.proto.to.non.object"
,
ScriptRuntime
.
safeToString
(
this
),
ScriptRuntime
.
safeToString
(
newProto
));
}
...
...
@@ -2012,11 +2011,11 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
final
ScriptObject
owner
=
find
.
getOwner
();
final
Class
<
ClassCastException
>
exception
=
explicitInstanceOfCheck
?
null
:
ClassCastException
.
class
;
final
SwitchPoint
protoSwitchPoint
;
final
SwitchPoint
[]
protoSwitchPoints
;
if
(
mh
==
null
)
{
mh
=
Lookup
.
emptyGetter
(
returnType
);
protoSwitchPoint
=
getProtoSwitchPoint
(
name
,
owner
);
protoSwitchPoint
s
=
getProtoSwitchPoints
(
name
,
owner
);
}
else
if
(!
find
.
isSelf
())
{
assert
mh
.
type
().
returnType
().
equals
(
returnType
)
:
"return type mismatch for getter "
+
mh
.
type
().
returnType
()
+
" != "
+
returnType
;
...
...
@@ -2024,12 +2023,12 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
// Add a filter that replaces the self object with the prototype owning the property.
mh
=
addProtoFilter
(
mh
,
find
.
getProtoChainLength
());
}
protoSwitchPoint
=
getProtoSwitchPoint
(
name
,
owner
);
protoSwitchPoint
s
=
getProtoSwitchPoints
(
name
,
owner
);
}
else
{
protoSwitchPoint
=
null
;
protoSwitchPoint
s
=
null
;
}
final
GuardedInvocation
inv
=
new
GuardedInvocation
(
mh
,
guard
,
protoSwitchPoint
,
exception
);
final
GuardedInvocation
inv
=
new
GuardedInvocation
(
mh
,
guard
,
protoSwitchPoint
s
,
exception
);
return
inv
.
addSwitchPoint
(
findBuiltinSwitchPoint
(
name
));
}
...
...
@@ -2128,17 +2127,32 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
* @param owner the property owner, null if property is not defined
* @return a SwitchPoint or null
*/
public
final
SwitchPoint
getProtoSwitchPoint
(
final
String
name
,
final
ScriptObject
owner
)
{
public
final
SwitchPoint
[]
getProtoSwitchPoints
(
final
String
name
,
final
ScriptObject
owner
)
{
if
(
owner
==
this
||
getProto
()
==
null
)
{
return
null
;
}
final
List
<
SwitchPoint
>
switchPoints
=
new
ArrayList
<>();
for
(
ScriptObject
obj
=
this
;
obj
!=
owner
&&
obj
.
getProto
()
!=
null
;
obj
=
obj
.
getProto
())
{
final
ScriptObject
parent
=
obj
.
getProto
();
parent
.
getMap
().
addListener
(
name
,
obj
.
getMap
());
final
SwitchPoint
sp
=
parent
.
getMap
().
getSharedProtoSwitchPoint
();
if
(
sp
!=
null
&&
!
sp
.
hasBeenInvalidated
())
{
switchPoints
.
add
(
sp
);
}
}
return
getMap
().
getSwitchPoint
(
name
);
switchPoints
.
add
(
getMap
().
getSwitchPoint
(
name
));
return
switchPoints
.
toArray
(
new
SwitchPoint
[
switchPoints
.
size
()]);
}
private
void
checkSharedProtoMap
()
{
// Check if our map has an expected shared prototype property map. If it has, make sure that
// the prototype map has not been invalidated, and that it does match the actual map of the prototype.
if
(
getMap
().
isInvalidSharedMapFor
(
getProto
()))
{
// Change our own map to one that does not assume a shared prototype map.
setMap
(
getMap
().
makeUnsharedCopy
());
}
}
/**
...
...
@@ -2220,7 +2234,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
return
new
GuardedInvocation
(
Lookup
.
EMPTY_SETTER
,
NashornGuards
.
getMapGuard
(
getMap
(),
explicitInstanceOfCheck
),
getProtoSwitchPoint
(
name
,
null
),
getProtoSwitchPoint
s
(
name
,
null
),
explicitInstanceOfCheck
?
null
:
ClassCastException
.
class
);
}
...
...
@@ -2366,7 +2380,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
find
.
getGetter
(
Object
.
class
,
INVALID_PROGRAM_POINT
,
request
),
find
.
getProtoChainLength
(),
func
),
getProtoSwitchPoint
(
NO_SUCH_PROPERTY_NAME
,
find
.
getOwner
()),
getProtoSwitchPoint
s
(
NO_SUCH_PROPERTY_NAME
,
find
.
getOwner
()),
//TODO this doesn't need a ClassCastException as guard always checks script object
null
);
}
...
...
@@ -2438,7 +2452,7 @@ public abstract class ScriptObject implements PropertyAccess, Cloneable {
}
return
new
GuardedInvocation
(
Lookup
.
emptyGetter
(
desc
.
getMethodType
().
returnType
()),
NashornGuards
.
getMapGuard
(
getMap
(),
explicitInstanceOfCheck
),
getProtoSwitchPoint
(
name
,
null
),
NashornGuards
.
getMapGuard
(
getMap
(),
explicitInstanceOfCheck
),
getProtoSwitchPoint
s
(
name
,
null
),
explicitInstanceOfCheck
?
null
:
ClassCastException
.
class
);
}
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SetMethodCreator.java
浏览文件 @
b642e31e
...
...
@@ -186,10 +186,7 @@ final class SetMethodCreator {
private
SetMethod
createNewPropertySetter
(
final
SwitchPoint
builtinSwitchPoint
)
{
final
SetMethod
sm
=
map
.
getFreeFieldSlot
()
>
-
1
?
createNewFieldSetter
(
builtinSwitchPoint
)
:
createNewSpillPropertySetter
(
builtinSwitchPoint
);
final
PropertyListeners
listeners
=
map
.
getListeners
();
if
(
listeners
!=
null
)
{
listeners
.
propertyAdded
(
sm
.
property
);
}
map
.
propertyAdded
(
sm
.
property
,
true
);
return
sm
;
}
...
...
@@ -204,7 +201,7 @@ final class SetMethodCreator {
//fast type specific setter
final
MethodHandle
fastSetter
=
property
.
getSetter
(
type
,
newMap
);
//0 sobj, 1 value, slot folded for spill property already
//slow setter, that calls ScriptObject.set with appropr
ai
te type and key name
//slow setter, that calls ScriptObject.set with appropr
ia
te type and key name
MethodHandle
slowSetter
=
ScriptObject
.
SET_SLOW
[
getAccessorTypeIndex
(
type
)];
slowSetter
=
MH
.
insertArguments
(
slowSetter
,
3
,
NashornCallSiteDescriptor
.
getFlags
(
desc
));
slowSetter
=
MH
.
insertArguments
(
slowSetter
,
1
,
name
);
...
...
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/SharedPropertyMap.java
0 → 100644
浏览文件 @
b642e31e
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package
jdk.nashorn.internal.runtime
;
import
java.lang.invoke.SwitchPoint
;
/**
* This class represents a property map that can be shared among multiple prototype objects, allowing all inheriting
* top-level objects to also share one property map. This is class is only used for prototype objects, the
* top-level objects use ordinary {@link PropertyMap}s with the {@link PropertyMap#sharedProtoMap} field
* set to the expected shared prototype map.
*
* <p>When an instance of this class is evolved because a property is added, removed, or modified in an object
* using it, the {@link #invalidateSwitchPoint()} method is invoked to signal to all callsites and inheriting
* objects that the assumption of a single shared prototype map is no longer valid. The property map resulting
* from the modification will no longer be an instance of this class.</p>
*/
public
final
class
SharedPropertyMap
extends
PropertyMap
{
private
SwitchPoint
switchPoint
;
private
static
final
long
serialVersionUID
=
2166297719721778876L
;
/**
* Create a new shared property map from the given {@code map}.
* @param map property map to copy
*/
public
SharedPropertyMap
(
final
PropertyMap
map
)
{
super
(
map
);
this
.
switchPoint
=
new
SwitchPoint
();
}
@Override
public
void
propertyAdded
(
final
Property
property
,
final
boolean
isSelf
)
{
if
(
isSelf
)
{
invalidateSwitchPoint
();
}
super
.
propertyAdded
(
property
,
isSelf
);
}
@Override
public
void
propertyDeleted
(
final
Property
property
,
final
boolean
isSelf
)
{
if
(
isSelf
)
{
invalidateSwitchPoint
();
}
super
.
propertyDeleted
(
property
,
isSelf
);
}
@Override
public
void
propertyModified
(
final
Property
oldProperty
,
final
Property
newProperty
,
final
boolean
isSelf
)
{
if
(
isSelf
)
{
invalidateSwitchPoint
();
}
super
.
propertyModified
(
oldProperty
,
newProperty
,
isSelf
);
}
@Override
synchronized
boolean
isValidSharedProtoMap
()
{
return
switchPoint
!=
null
;
}
@Override
synchronized
SwitchPoint
getSharedProtoSwitchPoint
()
{
return
switchPoint
;
}
/**
* Invalidate the shared prototype switch point if this is a shared prototype map.
*/
synchronized
void
invalidateSwitchPoint
()
{
if
(
switchPoint
!=
null
)
{
assert
!
switchPoint
.
hasBeenInvalidated
();
SwitchPoint
.
invalidateAll
(
new
SwitchPoint
[]{
switchPoint
});
switchPoint
=
null
;
}
}
}
nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/WithObject.java
浏览文件 @
b642e31e
...
...
@@ -46,7 +46,7 @@ import jdk.nashorn.internal.runtime.linker.NashornGuards;
*
*/
public
final
class
WithObject
extends
Scope
{
private
static
final
MethodHandle
WITHEXPRESSIONGUARD
=
findOwnMH
(
"withExpressionGuard"
,
boolean
.
class
,
Object
.
class
,
PropertyMap
.
class
,
SwitchPoint
.
class
);
private
static
final
MethodHandle
WITHEXPRESSIONGUARD
=
findOwnMH
(
"withExpressionGuard"
,
boolean
.
class
,
Object
.
class
,
PropertyMap
.
class
,
SwitchPoint
[]
.
class
);
private
static
final
MethodHandle
WITHEXPRESSIONFILTER
=
findOwnMH
(
"withFilterExpression"
,
Object
.
class
,
Object
.
class
);
private
static
final
MethodHandle
WITHSCOPEFILTER
=
findOwnMH
(
"withFilterScope"
,
Object
.
class
,
Object
.
class
);
private
static
final
MethodHandle
BIND_TO_EXPRESSION_OBJ
=
findOwnMH
(
"bindToExpression"
,
Object
.
class
,
Object
.
class
,
Object
.
class
);
...
...
@@ -360,13 +360,24 @@ public final class WithObject extends Scope {
private
MethodHandle
expressionGuard
(
final
String
name
,
final
ScriptObject
owner
)
{
final
PropertyMap
map
=
expression
.
getMap
();
final
SwitchPoint
sp
=
expression
.
getProtoSwitchPoint
(
name
,
owner
);
final
SwitchPoint
[]
sp
=
expression
.
getProtoSwitchPoints
(
name
,
owner
);
return
MH
.
insertArguments
(
WITHEXPRESSIONGUARD
,
1
,
map
,
sp
);
}
@SuppressWarnings
(
"unused"
)
private
static
boolean
withExpressionGuard
(
final
Object
receiver
,
final
PropertyMap
map
,
final
SwitchPoint
sp
)
{
return
((
WithObject
)
receiver
).
expression
.
getMap
()
==
map
&&
(
sp
==
null
||
!
sp
.
hasBeenInvalidated
());
private
static
boolean
withExpressionGuard
(
final
Object
receiver
,
final
PropertyMap
map
,
final
SwitchPoint
[]
sp
)
{
return
((
WithObject
)
receiver
).
expression
.
getMap
()
==
map
&&
!
hasBeenInvalidated
(
sp
);
}
private
static
boolean
hasBeenInvalidated
(
final
SwitchPoint
[]
switchPoints
)
{
if
(
switchPoints
!=
null
)
{
for
(
final
SwitchPoint
switchPoint
:
switchPoints
)
{
if
(
switchPoint
.
hasBeenInvalidated
())
{
return
true
;
}
}
}
return
false
;
}
/**
...
...
nashorn/test/script/basic/JDK-8134569.js
浏览文件 @
b642e31e
...
...
@@ -62,67 +62,146 @@ function createDeep() {
return
new
C
();
}
function
createDeeper
()
{
function
C
()
{
this
.
i1
=
1
;
this
.
i2
=
2
;
this
.
i3
=
3
;
return
this
;
}
function
D
()
{
this
.
p1
=
1
;
this
.
p2
=
2
;
this
.
p3
=
3
;
return
this
;
}
function
E
()
{
this
.
e1
=
1
;
this
.
e2
=
2
;
this
.
e3
=
3
;
return
this
;
}
D
.
prototype
=
new
E
();
C
.
prototype
=
new
D
();
return
new
C
();
}
function
createEval
()
{
return
eval
(
"
Object.create({})
"
);
}
function
p
(
o
)
{
print
(
o
.
x
)
}
var
a
,
b
;
function
e
(
o
)
{
print
(
o
.
e1
)
}
var
a
,
b
,
c
;
create
();
a
=
create
();
b
=
create
();
c
=
create
();
a
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
create
();
b
=
create
();
c
=
create
();
b
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
createEmpty
();
b
=
createEmpty
();
c
=
createEmpty
();
a
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
createEmpty
();
b
=
createEmpty
();
c
=
createEmpty
();
b
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
createDeep
();
b
=
createDeep
();
c
=
createDeep
();
a
.
__proto__
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
createDeep
();
b
=
createDeep
();
c
=
createDeep
();
b
.
__proto__
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
createDeeper
();
b
=
createDeeper
();
c
=
createDeeper
();
a
.
__proto__
.
__proto__
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
createDeeper
();
b
=
createDeeper
();
c
=
createDeeper
();
b
.
__proto__
.
__proto__
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
createDeeper
();
b
=
createDeeper
();
c
=
createDeeper
();
a
.
__proto__
.
__proto__
=
null
;
e
(
a
);
e
(
b
);
e
(
c
);
a
=
createDeeper
();
b
=
createDeeper
();
c
=
createDeeper
();
b
.
__proto__
.
__proto__
=
null
;
e
(
a
);
e
(
b
);
e
(
c
);
a
=
createEval
();
b
=
createEval
();
c
=
createEval
();
a
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
a
=
createEval
();
b
=
createEval
();
c
=
createEval
();
b
.
__proto__
.
x
=
123
;
p
(
a
);
p
(
b
);
p
(
c
);
nashorn/test/script/basic/JDK-8134569.js.EXPECTED
浏览文件 @
b642e31e
123
undefined
undefined
undefined
123
undefined
123
undefined
undefined
undefined
123
undefined
123
undefined
undefined
undefined
123
undefined
123
undefined
undefined
undefined
123
undefined
undefined
1
1
1
undefined
1
123
undefined
undefined
undefined
123
undefined
nashorn/test/script/basic/JDK-8134609.js
0 → 100644
浏览文件 @
b642e31e
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* JDK-8134609: Allow constructors with same prototoype map to share the allocator map
*
* @test
* @run
* @fork
* @option -Dnashorn.debug
*/
function
createProto
(
members
)
{
function
P
()
{
for
(
var
id
in
members
)
{
if
(
members
.
hasOwnProperty
(
id
))
{
this
[
id
]
=
members
[
id
];
}
}
return
this
;
}
return
new
P
();
}
function
createSubclass
(
prototype
,
members
)
{
function
C
()
{
for
(
var
id
in
members
)
{
if
(
members
.
hasOwnProperty
(
id
))
{
this
[
id
]
=
members
[
id
];
}
}
return
this
;
}
C
.
prototype
=
prototype
;
return
new
C
();
}
function
assertP1
(
object
,
value
)
{
Assert
.
assertTrue
(
object
.
p1
===
value
);
}
// First prototype will have non-shared proto-map. Second and third will be shared.
var
proto0
=
createProto
({
p1
:
0
,
p2
:
1
});
var
proto1
=
createProto
({
p1
:
1
,
p2
:
2
});
var
proto2
=
createProto
({
p1
:
2
,
p2
:
3
});
Assert
.
assertTrue
(
Debug
.
map
(
proto1
)
===
Debug
.
map
(
proto2
));
assertP1
(
proto1
,
1
);
assertP1
(
proto2
,
2
);
// First instantiation will have a non-shared prototype map, from the second one
// maps will be shared until a different proto map comes along.
var
child0
=
createSubclass
(
proto1
,
{
c1
:
1
,
c2
:
2
});
var
child1
=
createSubclass
(
proto2
,
{
c1
:
2
,
c2
:
3
});
var
child2
=
createSubclass
(
proto1
,
{
c1
:
3
,
c2
:
4
});
var
child3
=
createSubclass
(
proto2
,
{
c1
:
1
,
c2
:
2
});
var
child4
=
createSubclass
(
proto0
,
{
c1
:
3
,
c2
:
2
});
Assert
.
assertTrue
(
Debug
.
map
(
child1
)
===
Debug
.
map
(
child2
));
Assert
.
assertTrue
(
Debug
.
map
(
child1
)
===
Debug
.
map
(
child3
));
Assert
.
assertTrue
(
Debug
.
map
(
child3
)
!==
Debug
.
map
(
child4
));
assertP1
(
child1
,
2
);
assertP1
(
child2
,
1
);
assertP1
(
child3
,
2
);
assertP1
(
child4
,
0
);
Assert
.
assertTrue
(
delete
proto2
.
p1
);
assertP1
(
child3
,
undefined
);
assertP1
(
child2
,
1
);
Assert
.
assertTrue
(
Debug
.
map
(
child1
)
!==
Debug
.
map
(
child3
));
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录