Property.java revision 1036:f0b5e3900a10
198943Sluigi/* 2117328Sluigi * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 398943Sluigi * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 498943Sluigi * 598943Sluigi * This code is free software; you can redistribute it and/or modify it 698943Sluigi * under the terms of the GNU General Public License version 2 only, as 798943Sluigi * published by the Free Software Foundation. Oracle designates this 898943Sluigi * particular file as subject to the "Classpath" exception as provided 998943Sluigi * by Oracle in the LICENSE file that accompanied this code. 1098943Sluigi * 1198943Sluigi * This code is distributed in the hope that it will be useful, but WITHOUT 1298943Sluigi * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1398943Sluigi * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1498943Sluigi * version 2 for more details (a copy is included in the LICENSE file that 1598943Sluigi * accompanied this code). 1698943Sluigi * 1798943Sluigi * You should have received a copy of the GNU General Public License version 1898943Sluigi * 2 along with this work; if not, write to the Free Software Foundation, 1998943Sluigi * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2098943Sluigi * 2198943Sluigi * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2298943Sluigi * or visit www.oracle.com if you need additional information or have any 23187604Sluigi * questions. 2498943Sluigi */ 2598943Sluigi 2698943Sluigipackage jdk.nashorn.internal.runtime; 2798943Sluigi 28187767Sluigiimport static jdk.nashorn.internal.runtime.PropertyDescriptor.CONFIGURABLE; 29187767Sluigiimport static jdk.nashorn.internal.runtime.PropertyDescriptor.ENUMERABLE; 3098943Sluigiimport static jdk.nashorn.internal.runtime.PropertyDescriptor.WRITABLE; 3198943Sluigiimport java.io.Serializable; 3298943Sluigiimport java.lang.invoke.MethodHandle; 3398943Sluigiimport java.lang.invoke.SwitchPoint; 3498943Sluigiimport java.util.Objects; 3598943Sluigiimport jdk.nashorn.internal.codegen.ObjectClassGenerator; 3698943Sluigi 3798943Sluigi/** 3898943Sluigi * This is the abstract superclass representing a JavaScript Property. 3998943Sluigi * The {@link PropertyMap} map links keys to properties, and consequently 40187604Sluigi * instances of this class make up the values in the PropertyMap 41136071Sgreen * 42136071Sgreen * @see PropertyMap 4398943Sluigi * @see AccessorProperty 44175659Srwatson * @see UserAccessorProperty 45175659Srwatson */ 46169424Smaximpublic abstract class Property implements Serializable { 4798943Sluigi /* 48165648Spiso * ECMA 8.6.1 Property Attributes 49136071Sgreen * 50145246Sbrooks * We use negative flags because most properties are expected to 5198943Sluigi * be 'writable', 'configurable' and 'enumerable'. With negative flags, 5298943Sluigi * we can use leave flag byte initialized with (the default) zero value. 5398943Sluigi */ 5498943Sluigi 55145246Sbrooks /** Mask for property being both writable, enumerable and configurable */ 5698943Sluigi public static final int WRITABLE_ENUMERABLE_CONFIGURABLE = 0b0000_0000_0000; 5798943Sluigi 5898943Sluigi /** ECMA 8.6.1 - Is this property not writable? */ 5998943Sluigi public static final int NOT_WRITABLE = 1 << 0; 60165648Spiso 6198943Sluigi /** ECMA 8.6.1 - Is this property not enumerable? */ 62187767Sluigi public static final int NOT_ENUMERABLE = 1 << 1; 6398943Sluigi 64187767Sluigi /** ECMA 8.6.1 - Is this property not configurable? */ 65187764Sluigi public static final int NOT_CONFIGURABLE = 1 << 2; 66159636Soleg 67159636Soleg private static final int MODIFY_MASK = NOT_WRITABLE | NOT_ENUMERABLE | NOT_CONFIGURABLE; 68159636Soleg 69159636Soleg /** Is this a function parameter? */ 70159636Soleg public static final int IS_PARAMETER = 1 << 3; 71159636Soleg 72159636Soleg /** Is parameter accessed thru arguments? */ 73159636Soleg public static final int HAS_ARGUMENTS = 1 << 4; 74159636Soleg 75159636Soleg /** Is this a function declaration property ? */ 76159636Soleg public static final int IS_FUNCTION_DECLARATION = 1 << 5; 77159636Soleg 78159636Soleg /** 79159636Soleg * Is this is a primitive field given to us by Nasgen, i.e. 80159636Soleg * something we can be sure remains a constant whose type 81159636Soleg * is narrower than object, e.g. Math.PI which is declared 82159636Soleg * as a double 83159636Soleg */ 84159636Soleg public static final int IS_NASGEN_PRIMITIVE = 1 << 6; 85159636Soleg 86159636Soleg /** Is this a builtin property, e.g. Function.prototype.apply */ 87159636Soleg public static final int IS_BUILTIN = 1 << 7; 88159636Soleg 89159636Soleg /** Is this property bound to a receiver? This means get/set operations will be delegated to 90159636Soleg * a statically defined object instead of the object passed as callsite parameter. */ 91159636Soleg public static final int IS_BOUND = 1 << 7; 92159636Soleg 93158879Soleg /** Is this a lexically scoped LET or CONST variable that is dead until it is declared. */ 94158879Soleg public static final int NEEDS_DECLARATION = 1 << 8; 95187762Sluigi 96187762Sluigi /** Property key. */ 97187762Sluigi private final String key; 98187762Sluigi 99187762Sluigi /** Property flags. */ 100187762Sluigi private int flags; 101187762Sluigi 102187762Sluigi /** Property field number or spill slot. */ 103187762Sluigi private final int slot; 104187762Sluigi 105159636Soleg /** SwitchPoint that is invalidated when property is changed, optional */ 10698943Sluigi protected transient SwitchPoint builtinSwitchPoint; 10798943Sluigi 10898943Sluigi private static final long serialVersionUID = 2099814273074501176L; 10998943Sluigi 11098943Sluigi /** 11198943Sluigi * Constructor 11298943Sluigi * 11398943Sluigi * @param key property key 11498943Sluigi * @param flags property flags 11598943Sluigi * @param slot property field number or spill slot 11698943Sluigi */ 11798943Sluigi Property(final String key, final int flags, final int slot) { 11898943Sluigi assert key != null; 11998943Sluigi this.key = key; 12098943Sluigi this.flags = flags; 12198943Sluigi this.slot = slot; 12298943Sluigi } 12398943Sluigi 12498943Sluigi /** 12598943Sluigi * Copy constructor 12698943Sluigi * 12798943Sluigi * @param property source property 12898943Sluigi */ 12998943Sluigi Property(final Property property, final int flags) { 13098943Sluigi this.key = property.key; 13198943Sluigi this.slot = property.slot; 13298943Sluigi this.builtinSwitchPoint = property.builtinSwitchPoint; 13398943Sluigi this.flags = flags; 13498943Sluigi } 13598943Sluigi 13698943Sluigi /** 13798943Sluigi * Copy function 13898943Sluigi * 13998943Sluigi * @return cloned property 14098943Sluigi */ 14198943Sluigi public abstract Property copy(); 14298943Sluigi 14398943Sluigi /** 14498943Sluigi * Copy function 14598943Sluigi * 14698943Sluigi * @param newType new type 147172801Srpaulo * @return cloned property with new type 148172801Srpaulo */ 14998943Sluigi public abstract Property copy(final Class<?> newType); 15098943Sluigi 15198943Sluigi /** 15298943Sluigi * Property flag utility method for {@link PropertyDescriptor}s. Given two property descriptors, 15398943Sluigi * return the result of merging their flags. 15498943Sluigi * 15598943Sluigi * @param oldDesc first property descriptor 15698943Sluigi * @param newDesc second property descriptor 15798943Sluigi * @return merged flags. 15898943Sluigi */ 15998943Sluigi static int mergeFlags(final PropertyDescriptor oldDesc, final PropertyDescriptor newDesc) { 16098943Sluigi int propFlags = 0; 16198943Sluigi boolean value; 16298943Sluigi 16398943Sluigi value = newDesc.has(CONFIGURABLE) ? newDesc.isConfigurable() : oldDesc.isConfigurable(); 16498943Sluigi if (!value) { 16598943Sluigi propFlags |= NOT_CONFIGURABLE; 16698943Sluigi } 16798943Sluigi 16898943Sluigi value = newDesc.has(ENUMERABLE) ? newDesc.isEnumerable() : oldDesc.isEnumerable(); 16998943Sluigi if (!value) { 17098943Sluigi propFlags |= NOT_ENUMERABLE; 17198943Sluigi } 17298943Sluigi 17398943Sluigi value = newDesc.has(WRITABLE) ? newDesc.isWritable() : oldDesc.isWritable(); 17498943Sluigi if (!value) { 17598943Sluigi propFlags |= NOT_WRITABLE; 17698943Sluigi } 17798943Sluigi 17898943Sluigi return propFlags; 17998943Sluigi } 18098943Sluigi 18198943Sluigi /** 18298943Sluigi * Set the change callback for this property, i.e. a SwitchPoint 18398943Sluigi * that will be invalidated when the value of the property is 18498943Sluigi * changed 18598943Sluigi * @param sp SwitchPoint to use for change callback 18698943Sluigi */ 18798943Sluigi public final void setBuiltinSwitchPoint(final SwitchPoint sp) { 18898943Sluigi this.builtinSwitchPoint = sp; 18998943Sluigi } 19098943Sluigi 19198943Sluigi /** 19298943Sluigi * Builtin properties have an invalidation switchpoint that is 19398943Sluigi * invalidated when they are set, this is a getter for it 19498943Sluigi * @return builtin switchpoint, or null if none 19598943Sluigi */ 19698943Sluigi public final SwitchPoint getBuiltinSwitchPoint() { 19798943Sluigi return builtinSwitchPoint; 19898943Sluigi } 19998943Sluigi 200101641Sluigi /** 201101641Sluigi * Checks if this is a builtin property, this means that it has 20298943Sluigi * a builtin switchpoint that hasn't been invalidated by a setter 20398943Sluigi * @return true if builtin, untouched (unset) property 20498943Sluigi */ 20598943Sluigi public boolean isBuiltin() { 20698943Sluigi return builtinSwitchPoint != null && !builtinSwitchPoint.hasBeenInvalidated(); 20798943Sluigi } 20898943Sluigi 209141351Sglebius /** 210141351Sglebius * Property flag utility method for {@link PropertyDescriptor}. Get the property flags 21198943Sluigi * conforming to any Property using this PropertyDescriptor 21298943Sluigi * 21398943Sluigi * @param desc property descriptor 21498943Sluigi * @return flags for properties that conform to property descriptor 21598943Sluigi */ 21698943Sluigi static int toFlags(final PropertyDescriptor desc) { 21798943Sluigi int propFlags = 0; 218165648Spiso 21998943Sluigi if (!desc.isConfigurable()) { 220136071Sgreen propFlags |= NOT_CONFIGURABLE; 221136071Sgreen } 222158879Soleg if (!desc.isEnumerable()) { 223158879Soleg propFlags |= NOT_ENUMERABLE; 224136071Sgreen } 225158879Soleg if (!desc.isWritable()) { 22698943Sluigi propFlags |= NOT_WRITABLE; 22798943Sluigi } 228133600Scsjp 22998943Sluigi return propFlags; 23098943Sluigi } 23198943Sluigi 23298943Sluigi /** 23398943Sluigi * Check whether this property has a user defined getter function. See {@link UserAccessorProperty} 234136073Sgreen * @param obj object containing getter 235136073Sgreen * @return true if getter function exists, false is default 236136073Sgreen */ 23798943Sluigi public boolean hasGetterFunction(final ScriptObject obj) { 23898943Sluigi return false; 23998943Sluigi } 24098943Sluigi 24198943Sluigi /** 24298943Sluigi * Check whether this property has a user defined setter function. See {@link UserAccessorProperty} 24398943Sluigi * @param obj object containing setter 24498943Sluigi * @return true if getter function exists, false is default 24598943Sluigi */ 24698943Sluigi public boolean hasSetterFunction(final ScriptObject obj) { 24798943Sluigi return false; 24898943Sluigi } 24998943Sluigi 250136075Sgreen /** 25198943Sluigi * Check whether this property is writable (see ECMA 8.6.1) 25298943Sluigi * @return true if writable 25398943Sluigi */ 25498943Sluigi public boolean isWritable() { 25598943Sluigi return (flags & NOT_WRITABLE) == 0; 25698943Sluigi } 257102087Sluigi 258102087Sluigi /** 259112250Scjc * Check whether this property is writable (see ECMA 8.6.1) 260128575Sandre * @return true if configurable 261133387Sandre */ 262117241Sluigi public boolean isConfigurable() { 263117469Sluigi return (flags & NOT_CONFIGURABLE) == 0; 26498943Sluigi } 26598943Sluigi 266101978Sluigi /** 26798943Sluigi * Check whether this property is enumerable (see ECMA 8.6.1) 26898943Sluigi * @return true if enumerable 26998943Sluigi */ 27098943Sluigi public boolean isEnumerable() { 27198943Sluigi return (flags & NOT_ENUMERABLE) == 0; 27298943Sluigi } 27398943Sluigi 27498943Sluigi /** 27598943Sluigi * Check whether this property is used as a function parameter 27698943Sluigi * @return true if parameter 27798943Sluigi */ 27898943Sluigi public boolean isParameter() { 27998943Sluigi return (flags & IS_PARAMETER) == IS_PARAMETER; 28098943Sluigi } 281165648Spiso 282165648Spiso /** 283165648Spiso * Check whether this property is in an object with arguments field 284165648Spiso * @return true if has arguments 285165648Spiso */ 286165648Spiso public boolean hasArguments() { 287165648Spiso return (flags & HAS_ARGUMENTS) == HAS_ARGUMENTS; 288165648Spiso } 289165648Spiso 290165648Spiso /** 291165648Spiso * Check whether this is a spill property, i.e. one that will not 292165648Spiso * be stored in a specially generated field in the property class. 293145246Sbrooks * The spill pool is maintained separately, as a growing Object array 294145246Sbrooks * in the {@link ScriptObject}. 295145246Sbrooks * 296145246Sbrooks * @return true if spill property 297145246Sbrooks */ 298145246Sbrooks public boolean isSpill() { 299145246Sbrooks return false; 300146894Smlaier } 301146894Smlaier 302149020Sbz /** 303149020Sbz * Is this property bound to a receiver? If this method returns {@code true} get and set operations 304178888Sjulian * will be delegated to a statically bound object instead of the object passed as parameter. 305178888Sjulian * 306178888Sjulian * @return true if this is a bound property 30798943Sluigi */ 30898943Sluigi public boolean isBound() { 30998943Sluigi return (flags & IS_BOUND) == IS_BOUND; 31098943Sluigi } 311101978Sluigi 31298943Sluigi /** 31398943Sluigi * Is this a LET or CONST property that needs to see its declaration before being usable? 31498943Sluigi * 31598943Sluigi * @return true if this is a block-scoped variable 31698943Sluigi */ 31798943Sluigi public boolean needsDeclaration() { 31898943Sluigi return (flags & NEEDS_DECLARATION) == NEEDS_DECLARATION; 31998943Sluigi } 32098943Sluigi 32198943Sluigi /** 32298943Sluigi * Add more property flags to the property. Properties are immutable here, 32398943Sluigi * so any property change that results in a larger flag set results in the 32498943Sluigi * property being cloned. Use only the return value 32598943Sluigi * 32698943Sluigi * @param propertyFlags flags to be OR:ed to the existing property flags 32799475Sluigi * @return new property if property set was changed, {@code this} otherwise 32898943Sluigi */ 329145246Sbrooks public Property addFlags(final int propertyFlags) { 330145246Sbrooks if ((this.flags & propertyFlags) != propertyFlags) { 331145246Sbrooks final Property cloned = this.copy(); 332145246Sbrooks cloned.flags |= propertyFlags; 333145246Sbrooks return cloned; 33498943Sluigi } 335117328Sluigi return this; 33698943Sluigi } 33798943Sluigi 338165648Spiso /** 339165648Spiso * Check if a flag is set for a property 340165648Spiso * @param property property 341165648Spiso * @param flag flag to check 342165648Spiso * @return true if flag is set 343165648Spiso */ 344165648Spiso public static boolean checkFlag(final Property property, final int flag) { 345165648Spiso return (property.getFlags() & flag) == flag; 346165648Spiso } 347165648Spiso 348165648Spiso /** 349165648Spiso * Get the flags for this property 350165648Spiso * @return property flags 351165648Spiso */ 352165648Spiso public int getFlags() { 353165648Spiso return flags; 35498943Sluigi } 35598943Sluigi 35698943Sluigi /** 35798943Sluigi * Get the modify flags for this property. The modify flags are the ECMA 8.6.1 35898943Sluigi * flags that decide if the Property is writable, configurable and/or enumerable. 35998943Sluigi * 36098943Sluigi * @return modify flags for property 36198943Sluigi */ 36298943Sluigi public int getModifyFlags() { 36398943Sluigi return flags & MODIFY_MASK; 364141351Sglebius } 365141351Sglebius 36698943Sluigi /** 36798943Sluigi * Remove property flags from the property. Properties are immutable here, 36898943Sluigi * so any property change that results in a smaller flag set results in the 36998943Sluigi * property being cloned. Use only the return value 37098943Sluigi * 37198943Sluigi * @param propertyFlags flags to be subtracted from the existing property flags 372149020Sbz * @return new property if property set was changed, {@code this} otherwise 37398943Sluigi */ 374149020Sbz public Property removeFlags(final int propertyFlags) { 37599475Sluigi if ((this.flags & propertyFlags) != 0) { 37698943Sluigi final Property cloned = this.copy(); 377117469Sluigi cloned.flags &= ~propertyFlags; 378165648Spiso return cloned; 379178888Sjulian } 380117328Sluigi return this; 38198943Sluigi } 38298943Sluigi 383136071Sgreen /** 384136071Sgreen * Reset the property for this property. Properties are immutable here, 385136071Sgreen * so any property change that results in a different flag sets results in the 386158879Soleg * property being cloned. Use only the return value 387158879Soleg * 388136071Sgreen * @param propertyFlags flags that are replacing from the existing property flags 389136071Sgreen * @return new property if property set was changed, {@code this} otherwise 390136071Sgreen */ 39198943Sluigi public Property setFlags(final int propertyFlags) { 392158879Soleg if (this.flags != propertyFlags) { 39398943Sluigi final Property cloned = this.copy(); 39498943Sluigi cloned.flags &= ~MODIFY_MASK; 395133600Scsjp cloned.flags |= propertyFlags & MODIFY_MASK; 39698943Sluigi return cloned; 39798943Sluigi } 39898943Sluigi return this; 39998943Sluigi } 40098943Sluigi 40198943Sluigi /** 402136073Sgreen * Abstract method for retrieving the getter for the property. We do not know 403136073Sgreen * anything about the internal representation when we request the getter, we only 404136073Sgreen * know that the getter will return the property as the given type. 40598943Sluigi * 40698943Sluigi * @param type getter return value type 40798943Sluigi * @return a getter for this property as {@code type} 40898943Sluigi */ 40998943Sluigi public abstract MethodHandle getGetter(final Class<?> type); 410178888Sjulian 41198943Sluigi /** 41298943Sluigi * Get an optimistic getter that throws an exception if type is not the known given one 41398943Sluigi * @param type type 41498943Sluigi * @param programPoint program point 41598943Sluigi * @return getter 41698943Sluigi */ 41798943Sluigi public abstract MethodHandle getOptimisticGetter(final Class<?> type, final int programPoint); 41898943Sluigi 41998943Sluigi /** 42098943Sluigi * Hook to initialize method handles after deserialization. 42198943Sluigi * 42298943Sluigi * @param structure the structure class 423136075Sgreen */ 42498943Sluigi abstract void initMethodHandles(final Class<?> structure); 42598943Sluigi 42698943Sluigi /** 42798943Sluigi * Get the key for this property. This key is an ordinary string. The "name". 42898943Sluigi * @return key for property 42998943Sluigi */ 43098943Sluigi public String getKey() { 43199909Sluigi return key; 43298943Sluigi } 433102087Sluigi 434102087Sluigi /** 435102087Sluigi * Get the field number or spill slot 436102087Sluigi * @return number/slot, -1 if none exists 437102087Sluigi */ 438102087Sluigi public int getSlot() { 439102087Sluigi return slot; 440102087Sluigi } 441112250Scjc 442128575Sandre /** 443133387Sandre * get the Object value of this property from {@code owner}. This allows to bypass creation of the 444117241Sluigi * getter MethodHandle for spill and user accessor properties. 445145246Sbrooks * 446145246Sbrooks * @param self the this object 447145246Sbrooks * @param owner the owner of the property 448145246Sbrooks * @return the property value 449145246Sbrooks */ 450145246Sbrooks public abstract int getIntValue(final ScriptObject self, final ScriptObject owner); 451146894Smlaier 452146894Smlaier /** 453145246Sbrooks * get the Object value of this property from {@code owner}. This allows to bypass creation of the 454145246Sbrooks * getter MethodHandle for spill and user accessor properties. 455145246Sbrooks * 456145246Sbrooks * @param self the this object 457117469Sluigi * @param owner the owner of the property 45898943Sluigi * @return the property value 45998943Sluigi */ 46098943Sluigi public abstract long getLongValue(final ScriptObject self, final ScriptObject owner); 46198943Sluigi 46298943Sluigi /** 463101641Sluigi * get the Object value of this property from {@code owner}. This allows to bypass creation of the 464101641Sluigi * getter MethodHandle for spill and user accessor properties. 465101641Sluigi * 466101641Sluigi * @param self the this object 467117328Sluigi * @param owner the owner of the property 46898943Sluigi * @return the property value 46998943Sluigi */ 470117328Sluigi public abstract double getDoubleValue(final ScriptObject self, final ScriptObject owner); 471117328Sluigi 472117328Sluigi /** 473115793Sticso * get the Object value of this property from {@code owner}. This allows to bypass creation of the 474115793Sticso * getter MethodHandle for spill and user accessor properties. 475115793Sticso * 476129389Sstefanf * @param self the this object 477115793Sticso * @param owner the owner of the property 478187767Sluigi * @return the property value 479187716Sluigi */ 480187716Sluigi public abstract Object getObjectValue(final ScriptObject self, final ScriptObject owner); 481187716Sluigi 482187716Sluigi /** 483187716Sluigi * Set the value of this property in {@code owner}. This allows to bypass creation of the 484187716Sluigi * setter MethodHandle for spill and user accessor properties. 485187716Sluigi * 486187716Sluigi * @param self the this object 487187716Sluigi * @param owner the owner object 488187767Sluigi * @param value the new property value 489187716Sluigi * @param strict is this a strict setter? 490187716Sluigi */ 491187716Sluigi public abstract void setValue(final ScriptObject self, final ScriptObject owner, final int value, final boolean strict); 492187716Sluigi 493187716Sluigi /** 494187716Sluigi * Set the value of this property in {@code owner}. This allows to bypass creation of the 495187716Sluigi * setter MethodHandle for spill and user accessor properties. 496187716Sluigi * 497187716Sluigi * @param self the this object 498117328Sluigi * @param owner the owner object 499117328Sluigi * @param value the new property value 500117328Sluigi * @param strict is this a strict setter? 501117469Sluigi */ 502119740Stmm public abstract void setValue(final ScriptObject self, final ScriptObject owner, final long value, final boolean strict); 503117328Sluigi 504117328Sluigi /** 505117328Sluigi * Set the value of this property in {@code owner}. This allows to bypass creation of the 506117577Sluigi * setter MethodHandle for spill and user accessor properties. 507187764Sluigi * 508117328Sluigi * @param self the this object 509117328Sluigi * @param owner the owner object 510117328Sluigi * @param value the new property value 511117328Sluigi * @param strict is this a strict setter? 512117328Sluigi */ 513117328Sluigi public abstract void setValue(final ScriptObject self, final ScriptObject owner, final double value, final boolean strict); 514117328Sluigi 515117328Sluigi /** 516130281Sru * Set the value of this property in {@code owner}. This allows to bypass creation of the 517165648Spiso * setter MethodHandle for spill and user accessor properties. 518165648Spiso * 519165648Spiso * @param self the this object 520117328Sluigi * @param owner the owner object 521117328Sluigi * @param value the new property value 522117328Sluigi * @param strict is this a strict setter? 523117328Sluigi */ 524117328Sluigi public abstract void setValue(final ScriptObject self, final ScriptObject owner, final Object value, final boolean strict); 525117328Sluigi 526117328Sluigi /** 52798943Sluigi * Abstract method for retrieving the setter for the property. We do not know 52898943Sluigi * anything about the internal representation when we request the setter, we only 529117328Sluigi * know that the setter will take the property as a parameter of the given type. 53098943Sluigi * <p> 53198943Sluigi * Note that we have to pass the current property map from which we retrieved 53298943Sluigi * the property here. This is necessary for map guards if, e.g. the internal 53398943Sluigi * representation of the field, and consequently also the setter, changes. Then 53498943Sluigi * we automatically get a map guard that relinks the call site so that the 535117469Sluigi * older setter will never be used again. 53698943Sluigi * <p> 53798943Sluigi * see {@link ObjectClassGenerator#createSetter(Class, Class, MethodHandle, MethodHandle)} 53898943Sluigi * if you are interested in the internal details of this. Note that if you 53998943Sluigi * are running in default mode, with {@code -Dnashorn.fields.dual=true}, disabled, the setters 54098943Sluigi * will currently never change, as all properties are represented as Object field, 541129389Sstefanf * the Object fields are Initialized to {@code ScriptRuntime.UNDEFINED} and primitives are 54298943Sluigi * boxed/unboxed upon every access, which is not necessarily optimal 543117328Sluigi * 544117328Sluigi * @param type setter parameter type 545117328Sluigi * @param currentMap current property map for property 546117328Sluigi * @return a getter for this property as {@code type} 547117469Sluigi */ 548117469Sluigi public abstract MethodHandle getSetter(final Class<?> type, final PropertyMap currentMap); 54998943Sluigi 55098943Sluigi /** 55198943Sluigi * Get the user defined getter function if one exists. Only {@link UserAccessorProperty} instances 55298943Sluigi * can have user defined getters 55398943Sluigi * @param obj the script object 55498943Sluigi * @return user defined getter function, or {@code null} if none exists 55598943Sluigi */ 55698943Sluigi public ScriptFunction getGetterFunction(final ScriptObject obj) { 557140271Sbrooks return null; 558140271Sbrooks } 559140271Sbrooks 560140271Sbrooks /** 561140271Sbrooks * Get the user defined setter function if one exists. Only {@link UserAccessorProperty} instances 562140271Sbrooks * can have user defined getters 563140271Sbrooks * @param obj the script object 564140271Sbrooks * @return user defined getter function, or {@code null} if none exists 565187767Sluigi */ 566140271Sbrooks public ScriptFunction getSetterFunction(final ScriptObject obj) { 567140271Sbrooks return null; 568140271Sbrooks } 569140271Sbrooks 570140271Sbrooks @Override 571140271Sbrooks public int hashCode() { 572140271Sbrooks final Class<?> type = getCurrentType(); 573140271Sbrooks return Objects.hashCode(this.key) ^ flags ^ getSlot() ^ (type == null ? 0 : type.hashCode()); 574140271Sbrooks } 575140271Sbrooks 576140271Sbrooks @Override 577140271Sbrooks public boolean equals(final Object other) { 578140271Sbrooks if (this == other) { 579140271Sbrooks return true; 580140271Sbrooks } 581140271Sbrooks 582140271Sbrooks if (other == null || this.getClass() != other.getClass()) { 583140271Sbrooks return false; 584140271Sbrooks } 585140271Sbrooks 586140271Sbrooks final Property otherProperty = (Property)other; 587140271Sbrooks 588140271Sbrooks return equalsWithoutType(otherProperty) && 589140271Sbrooks getCurrentType() == otherProperty.getCurrentType(); 590140271Sbrooks } 591140271Sbrooks 592140271Sbrooks boolean equalsWithoutType(final Property otherProperty) { 593140271Sbrooks return getFlags() == otherProperty.getFlags() && 594140271Sbrooks getSlot() == otherProperty.getSlot() && 595140271Sbrooks getKey().equals(otherProperty.getKey()); 596140271Sbrooks } 597140271Sbrooks 598140271Sbrooks private static final String type(final Class<?> type) { 599140271Sbrooks if (type == null) { 600140271Sbrooks return "undef"; 601140271Sbrooks } else if (type == int.class) { 602140271Sbrooks return "i"; 603140271Sbrooks } else if (type == long.class) { 604140271Sbrooks return "j"; 605140271Sbrooks } else if (type == double.class) { 606140271Sbrooks return "d"; 60798943Sluigi } else { 60898943Sluigi return "o"; 60998943Sluigi } 610117328Sluigi } 61198943Sluigi 61298943Sluigi /** 61398943Sluigi * Short toString version 614117469Sluigi * @return short toString 61598943Sluigi */ 616187764Sluigi public final String toStringShort() { 61798943Sluigi final StringBuilder sb = new StringBuilder(); 61898943Sluigi final Class<?> type = getCurrentType(); 61998943Sluigi sb.append(getKey()).append(" (").append(type(type)).append(')'); 62098943Sluigi return sb.toString(); 62198943Sluigi } 622187764Sluigi 62398943Sluigi private static String indent(final String str, final int indent) { 62498943Sluigi final StringBuilder sb = new StringBuilder(); 62598943Sluigi sb.append(str); 62698943Sluigi for (int i = 0; i < indent - str.length(); i++) { 62798943Sluigi sb.append(' '); 62898943Sluigi } 62998943Sluigi return sb.toString(); 63098943Sluigi } 63198943Sluigi 63298943Sluigi @Override 63398943Sluigi public String toString() { 634117328Sluigi final StringBuilder sb = new StringBuilder(); 635117328Sluigi final Class<?> type = getCurrentType(); 636117328Sluigi 637117328Sluigi sb.append(indent(getKey(), 20)). 638117328Sluigi append(" id="). 639117328Sluigi append(Debug.id(this)). 640117328Sluigi append(" (0x"). 641136075Sgreen append(indent(Integer.toHexString(flags), 4)). 642158879Soleg append(") "). 643117328Sluigi append(getClass().getSimpleName()). 644117328Sluigi append(" {"). 645117328Sluigi append(indent(type(type), 5)). 64698943Sluigi append('}'); 647117328Sluigi 64898943Sluigi if (slot != -1) { 64998943Sluigi sb.append(" ["). 65098943Sluigi append("slot="). 651102087Sluigi append(slot). 65298943Sluigi append(']'); 653117328Sluigi } 65498943Sluigi 655117469Sluigi return sb.toString(); 65698943Sluigi } 657116690Sluigi 658117328Sluigi /** 659117328Sluigi * Get the current type of this field. If you are not running with dual fields enabled, 660116690Sluigi * this will always be Object.class. See the value representation explanation in 661116690Sluigi * {@link Property#getSetter(Class, PropertyMap)} and {@link ObjectClassGenerator} 662116690Sluigi * for more information. 663116690Sluigi * 66498943Sluigi * @return current type of property, null means undefined 66598943Sluigi */ 66698943Sluigi public abstract Class<?> getCurrentType(); 66798943Sluigi 66898943Sluigi /** 66998943Sluigi * Reset the current type of this property 67098943Sluigi * @param currentType new current type 67198943Sluigi */ 67298943Sluigi public abstract void setCurrentType(final Class<?> currentType); 67398943Sluigi 67498943Sluigi /** 67598943Sluigi * Check whether this Property can ever change its type. The default is false, and if 67698943Sluigi * you are not running with dual fields, the type is always object and can never change 67798943Sluigi * @return true if this property can change types 67898943Sluigi */ 67998943Sluigi public boolean canChangeType() { 68098943Sluigi return false; 68198943Sluigi } 682101628Sluigi 68398943Sluigi /** 68498943Sluigi * Check whether this property represents a function declaration. 68598943Sluigi * @return whether this property is a function declaration or not. 68698943Sluigi */ 687101628Sluigi public boolean isFunctionDeclaration() { 688101628Sluigi return (flags & IS_FUNCTION_DECLARATION) == IS_FUNCTION_DECLARATION; 68998943Sluigi } 69098943Sluigi} 691101628Sluigi