GETPROP: exposed property get algorithm 
Background 
Consider the following expression:
x = y[z]
The following happens compile time:
- zis parsed as an identifier reference
- yis parsed as an identifier reference
- y[z]is parsed as a property accessor (E5 Section 11.2.1)
- When the simple assignment is parsed, the y[z]compiler knows that the property accessor is used as a right-hand-side value, so it emits whatever internal bytecode is required to read the property value during execution
The following happens run time:
- The compiled code contains the sequence described in E5 Section 11.2.1: - baseValue = GetValue(y), where- yis the identifier reference
- propertyNameValue = GetValue(z), where- zis the identifier reference
- CheckObjectCoercible(baseValue), which throws a- TypeErrorif the- baseValueis- nullor- undefined
- Create a property reference with baseValueas the base reference andToString(propertyNameValue)as the property name (and strict flag based on current code strictness)
 
- Call GetValue()for the property reference. This results in the following sub-steps of E5 Section 8.7.1 to be executed:- baseis the result of- GetValue(y)(identifier lookup result directly)
- The referenced name is ToString(GetValue(z))(identifier lookup result with coercion)
- If baseis not a primitive: use[[Get]]directly forbaseand the referenced name
- Else use a variant for [[Get]]
 
The [[Get]] variant for a primitive base is specified explicitly in E5 Section 8.7.1. This seems a bit odd, as it seems equivalent to:
- Let ObeToObject(base)
- Call [[Get]]forOand referenced name
However, this is not the case. There is a subtle difference in the case that the property is an accessor. Normally the this binding for the getter is the object given to [[Get]]. Here the this binding is the uncoerced primitive value.
This leads to externally visible behavior, illustrated in the following:
// add test getter
Object.defineProperty(String.prototype, 'test', {
  get: function() { print(typeof this); },
  set: function(x) { print(typeof this); },
});
"foo".test;  // prints 'string'
var s = new String("foo");
s.test;      // prints 'object'
Behavior in ECMAScript implementations seems to vary:
- NodeJS / V8: prints 'string' and 'object' as expected
- Rhino: prints 'object' and 'object'
- Smjs: prints 'object' and 'object'
GetValue() allows the caller to skip creation of the coerced object (which is one of: a Boolean, a Number, or a String; see E5 Section 9.9, ToObject()).
Note: the replacement [[Get]] overrides whatever [[Get]] function would normally be used for the target object. For instance, if there were some primitive-to-object coercion which created an arguments object, the arguments object exotic [[Get]] behavior would be skipped. However, since the arguments and Function objects are the only objects with non-default [[Get]], this is not an issue in practice.
First draft 
When the property accessor is created, the base reference and property name are "coerced" to a value using GetValue(). In the example above, this causes x's and foo's values to be looked up. These correspond to steps 1-4 of the property accessor expression in E5 Section 11.2.1. When compiling, these are converted into whatever code is necessary to fetch the two values into VM registers.
The relevant part begins after that in steps 5-8, which first perform some coercions and then create a property accessor. The accessor is then acted upon by GetValue(), and ultimately [[Get]] or its variant.
Combining all of these, we get the first draft (for base value O and property name value P):
- Let origbeO. (Remember the uncoerced original for a possible getter call.)
- Call CheckObjectCoerciblewithOas argument. In practice: ifOisnullorundefined, throw aTypeError.
- Let PbeToString(P). (This may have side effects ifPis an object.)
- Let ObeToObject(O). (This is side effect free.)
- If Ois anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments object exotic behavior.) Letmapbe the value of the[[ParameterMap]]internal property of the arguments object. b. If the result of calling the[[GetOwnProperty]]internal method ofmappassingPas the argument is notundefined: 1. Return the result of calling the[[Get]]internal method ofmappassingPas the argument.
- Let descbe the result of calling the[[GetProperty]]internal method ofOwith property nameP.
- If descisundefined, returnundefined.
- If IsDataDescriptor(desc)istrue: a. Letresbedesc.[[Value]].
- Otherwise, IsAccessorDescriptor(desc)must betrue: a. Letgetterbedesc.[[Get]]. b. Ifgetterisundefined, returnundefined. c. Else letresbe the result of calling the[[Call]]internal method ofgetterprovidingorigas thethisvalue and providing no arguments. (Note: the difference to a basic[[Get]]is that the getterthisbinding is the original, uncoerced object.)
- If origis aFunctionobject or anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments or Function object exotic behavior.) IfPis"caller"andresis a strict modeFunctionobject, throw aTypeErrorexception.
- Return res.
Notes:
- Steps 2-3 come from the property accessor evaluation rules in E5 Section 11.2.1. In particular, - CheckObjectCoercible()is called before the key is coerced to a string. Since the key string coercion may have side effects, the order of evaluation matters.- Note that - ToObject()has no side effects (this can be seen from a case by case inspection), so steps 3 and 4 can be reversed.
- Step 4 comes from - GetValue().
- Steps 5 and forward come from - [[Get]]; here with exotic behaviors inlined, but- [[GetProperty]]not inlined.
We could inline the [[GetProperty]] call to the algorithm. However, because the current implementation doesn't do so, that has been omitted for now.
Improving type checking of base value 
A variant where steps 3 and 4 are reversed and expanded is as follows:
- Let origbeO. (Remember the uncoerced original for a possible getter call.)
- Check and/or coerce Oas follows: a. IfOisnullorundefined, throw aTypeError. (This is theCheckObjectCoerciblepart.) b. Else ifOis a boolean, a number, or a string, setOtoToObject(O). c. Else ifOis an object, do nothing. d. Throw aTypeError. (Note that this case should not happen, as steps a-c are exhaustive. However, this step is useful as a fallback, and for handling any internal types.)
- Let PbeToString(P). (This may have side effects ifPis an object.)
- If Ois anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments object exotic behavior.) Letmapbe the value of the[[ParameterMap]]internal property of the arguments object. b. If the result of calling the[[GetOwnProperty]]internal method ofmappassingPas the argument is notundefined: 1. Return the result of calling the[[Get]]internal method ofmappassingPas the argument.
- Let descbe the result of calling the[[GetProperty]]internal method ofOwith property nameP.
- If descisundefined, returnundefined.
- If IsDataDescriptor(desc)istrue: a. Letresbedesc.[[Value]].
- Otherwise, IsAccessorDescriptor(desc)must betrue: a. Letgetterbedesc.[[Get]]. b. Ifgetterisundefined, returnundefined. c. Else letresbe the result of calling the[[Call]]internal method ofgetterprovidingorigas thethisvalue and providing no arguments. (Note: the difference to a basic[[Get]]is that the getterthisbinding is the original, uncoerced object.)
- If origis aFunctionobject or anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments or Function object exotic behavior.) IfPis"caller"andresis a strict modeFunctionobject, throw aTypeErrorexception.
- Return res.
Avoiding temporary objects 
If the base value is not an object, step 4 in the above algorithm creates a temporary object given to [[GetProperty]] for a property descriptor lookup. The first object in the prototype chain is the temporary object, while the rest are already established non-temporary objects.
If we knew that the property P could never be an own property of the temporary object, we could skip creation of the temporary object altogether. Instead, we could simply start [[GetProperty]] from the internal prototype that the coerced object would get without actually creating the object.
Since the coerced object is created by ToObject from a primitive value, we know that it is a Boolean instance, a Number instance, or a String instance (see E5 Section 9.9). The "own properties" of these are:
- Boolean: none
- Number: none
- String:- "length"and index properties for string characters
So, the coercion can be skipped safely for everything except Strings. This is unfortunate, because it is conceivably the string primitive value which is most likely to be accessed through a coercion, e.g. as in:
var t = "my string";
print(t.length);
In any case, avoiding temporary creation for everything but Strings can be worked into the algorithm e.g. as follows:
- Let origbeO. (Remember the uncoerced original fora possible getter call.)
- Check and/or coerce Oas follows: a. IfOisnullorundefined, throw aTypeError. (This is theCheckObjectCoerciblepart.) b. IfOis a boolean: setOto the built-inBooleanprototype object (skip creation of temporary) c. Else ifOis a number: setOto the built-inNumberprototype object (skip creation of temporary) d. Else ifOis a string, setOtoToObject(O). e. Else ifOis an object, do nothing. f. Else, throw aTypeError. (Note that this case should not happen, as steps a-e are exhaustive. However, this step is useful as a fallback, and for handling any internal types.)
- Let PbeToString(P). (This may have side effects ifPis an object.)
- If Ois anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments object exotic behavior.) Letmapbe the value of the[[ParameterMap]]internal property of the arguments object. b. If the result of calling the[[GetOwnProperty]]internal method ofmappassingPas the argument is notundefined: 1. Return the result of calling the[[Get]]internal method ofmappassingPas the argument.
- Let descbe the result of calling the[[GetProperty]]internal method ofOwith property nameP.
- If descisundefined, returnundefined.
- If IsDataDescriptor(desc)istrue: a. Letresbedesc.[[Value]].
- Otherwise, IsAccessorDescriptor(desc)must betrue: a. Letgetterbedesc.[[Get]]. b. Ifgetterisundefined, returnundefined. c. Else letresbe the result of calling the[[Call]]internal method ofgetterprovidingorigas thethisvalue and providing no arguments. (Note: the difference to a basic[[Get]]is that the getterthisbinding is the original, uncoerced object.)
- If origis aFunctionobject or anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments or Function object exotic behavior.) IfPis"caller"andresis a strict modeFunctionobject, throw aTypeErrorexception.
- Return res.
If we change step 2.d to get the related string value (length or character of the string) directly, no temporaries need to be created due to coercion. However, if the property name P is checked, it needs to be string coerced which happens only later in step 3. If we add a separate coercion to step 2.d, P will be coerced twice unless step 3 is then explicitly skipped; this is not an issue as the latter coercion is a NOP and can in any case be easily skipped.
This variant is as follows:
- Let origbeO. (Remember the uncoerced original for a possible getter call.)
- Check and/or coerce Oas follows: a. IfOisnullorundefined, throw aTypeError. (This is theCheckObjectCoerciblepart.) b. IfOis a boolean: setOto the built-inBooleanprototype object (skip creation of temporary) c. Else ifOis a number: setOto the built-inNumberprototype object (skip creation of temporary) d. Else ifOis a string: 1. SetPtoToString(P). (This may have side effects ifPis an object.) 2. IfPislength, return the length of the primitive string value as a number. 3. IfPis a valid array index within the string length, return a one-character substring of the primitive string value at the specified index. 4. Else, setOto the built-inStringprototype object (skip creation of temporary) 5. Goto LOOKUP. (Avoid double coercion ofP.) e. Else ifOis an object, do nothing. f. Else, throw aTypeError. (Note that this case should not happen, as steps a-e are exhaustive. However, this step is useful as a fallback, and for handling any internal types.)
- Let PbeToString(P). (This may have side effects ifPis an object.)
- LOOKUP: If Ois anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments object exotic behavior.) Letmapbe the value of the[[ParameterMap]]internal property of the arguments object. b. If the result of calling the[[GetOwnProperty]]internal method ofmappassingPas the argument is notundefined: 1. Return the result of calling the[[Get]]internal method ofmappassingPas the argument.
- Let descbe the result of calling the[[GetProperty]]internal method ofOwith property nameP.
- If descisundefined, returnundefined.
- If IsDataDescriptor(desc)istrue: a. Letresbedesc.[[Value]].
- Otherwise, IsAccessorDescriptor(desc)must betrue: a. Letgetterbedesc.[[Get]]. b. Ifgetterisundefined, returnundefined. c. Else letresbe the result of calling the[[Call]]internal method ofgetterprovidingorigas thethisvalue and providing no arguments. (Note: the difference to a basic[[Get]]is that the getterthisbinding is the original, uncoerced object.)
- If origis aFunctionobject or anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments or Function object exotic behavior.) IfPis"caller"andresis a strict modeFunctionobject, throw aTypeErrorexception.
- Return res.
Fast path for array indices 
When the property name is a number and a valid array index, we'd prefer to be able to lookup the property without coercing the number to a string. This "fast path" needs to work for the common cases; rare cases can go through the ordinary algorithm which requires a ToString() coercion.
There are many ways to do a (compliant) fast path. The simple case we're considering here is the case when the target object has an "own property" matching the property name (a number).
A simple "shallow fast path" could be:
- If Pis a whole number in the range [0,2**32-2] (a valid array index) ANDOhas an array part ANDOhas no conflicting "exotic behaviors", then:- Let idxbe the array index represented byP
- If the array part of Ocontainsidxand the key exists, read and return the value. Note that the value can beundefined
 
- Let 
- Else use normal algorithm.
Some notes:
- The behavior of the fast path must match the behavior of the normal algorithm exactly (including side effects). This should be the case here, but can be verified by simulating the normal algorithm with the assumption of a number as a property name, with the target property present as an "own data property" of the target object. 
- The conflicting exotic behaviors are currently: - Stringobject exotic behavior, and arguments object exotic behavior. Array exotic behaviors are not conflicting for read operations.
- A certain key in the array can be defined even if the value is - undefined. The check is whether the key has been defined, i.e.- [[HasProperty]]would be true. Internally, the value "unused" is used to denote unused entries with unused keys, while the value "undefined" represents an undefined value with a defined key. For instance, the following defines an array key:- var a = []; a[10] = undefined; // "10" will now enumerate
- The fast path avoids the - ToString()coercion which may, in general, have side effects (at least for objects). However, the fast path only applies if- Pis a number, and the- ToString()coercion of a number is side effect free.
- If the array part does not contain the key, the normal algorithm is always used, regardless of whether the ancestors contain the key or not. This means that if a non-existent key is accessed from the array (even if the index is within the current array length), string interning will be required with this fast path. For instance: - var a = []; a[0] = 'foo'; a[2] = 'bar'; // fast path ok, no string interning print(a[0]); // fast path fails, string interned but still not found print(a[1]);
Inlining the above shallow fast path with the variant which avoids temporaries altogether produces:
- Let origbeO. (Remember the uncoerced original for a possible getter call.)
- Check and/or coerce Oas follows: a. IfOisnullorundefined, throw aTypeError. (This is theCheckObjectCoerciblepart.) b. IfOis a boolean: setOto the built-inBooleanprototype object (skip creation of temporary) c. Else ifOis a number: setOto the built-inNumberprototype object (skip creation of temporary) d. Else ifOis a string: 1. SetPtoToString(P). (This may have side effects ifPis an object.) 2. IfPislength, return the length of the primitive string value as a number. 3. IfPis a valid array index within the string length, return a one-character substring of the primitive string value at the specified index. 4. Else, setOto the built-inStringprototype object (skip creation of temporary) 5. Goto LOOKUP. (Avoid double coercion ofP.) e. Else ifOis an object: 1. Array fast path: IfOis an object (always true here) ANDPis a number and a valid array index (whole number in [0,2**32-2]) ANDOinternal representation has an array part ANDOdoes not have conflicting exotic behaviors (cannot haveStringor arguments exotic behaviors, may haveArraybehavior), then: a. Letidxbe the array index represented byPb. If the array part ofOcontainsidxand the key exists, read and return that value. (Note:ToString(P)is skipped, but it would have no side effects asPis a number. The"caller"check forPis also skipped, but it would never match becausePis a number.) f. Else, Throw aTypeError. (Note that this case should not happen, as steps a-e are exhaustive. However, this step is useful as a fallback, and for handling any internal types.)
- Let PbeToString(P). (This may have side effects ifPis an object.)
- LOOKUP: If Ois anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments object exotic behavior.) Letmapbe the value of the[[ParameterMap]]internal property of the arguments object. b. If the result of calling the[[GetOwnProperty]]internal method ofmappassingPas the argument is notundefined: 1. Return the result of calling the[[Get]]internal method ofmappassingPas the argument.
- Let descbe the result of calling the[[GetProperty]]internal method ofOwith property nameP.
- If descisundefined, returnundefined.
- If IsDataDescriptor(desc)istrue: a. Letresbedesc.[[Value]].
- Otherwise, IsAccessorDescriptor(desc)must betrue: a. Letgetterbedesc.[[Get]]. b. Ifgetterisundefined, returnundefined. c. Else letresbe the result of calling the[[Call]]internal method ofgetterprovidingorigas thethisvalue and providing no arguments. (Note: the difference to a basic[[Get]]is that the getterthisbinding is the original, uncoerced object.)
- If origis aFunctionobject or anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments or Function object exotic behavior.) IfPis"caller"andresis a strict modeFunctionobject, throw aTypeErrorexception.
- Return res.
We can further improve this by adding a fast path for the case where O is a primitive string (in step 2.d):
- Let origbeO. (Remember the uncoerced original fora possible getter call.)
- Check and/or coerce Oas follows: a. IfOisnullorundefined, throw aTypeError. (This is theCheckObjectCoerciblepart; the throw is unconditional.) b. IfOis a boolean: setOto the built-inBooleanprototype object (skip creation of temporary) c. Else ifOis a number: setOto the built-inNumberprototype object (skip creation of temporary) d. Else ifOis a string: 1. IfPis a number, is a whole number, a valid array index, and within the string length, return a one-character substring of the primitive string value at the specified index. (Note:ToString(P)is skipped, but it would have no side effects asPis a number. The"caller"check forPis also skipped, but it would never match becausePis a number.) 2. SetPtoToString(P). (This may have side effects ifPis an object.) 3. IfPislength, return the length of the primitive string value as a number. (Note: The"caller"check forPis skipped, but would never match.) 4. IfPis a valid array index within the string length, return a one-character substring of the primitive string value at the specified index. (Note: The"caller"check forPis skipped, but would never match.) 5. Else, setOto the built-inStringprototype object (skip creation of temporary) 6. Goto LOOKUP. (Avoid double coercion ofP.) e. Else ifOis an object: 1. Array fast path: IfOis an object (always true here) ANDPis a number and a valid array index (whole number in [0,2**32-2]) ANDOinternal representation has an array part ANDOdoes not have conflicting exotic behaviors (cannot haveStringor arguments exotic behaviors, may haveArraybehavior), then: a. Letidxbe the array index represented byPb. If the array part ofOcontainsidxand the key exists, read and return that value. (Note:ToString(P)is skipped, but it would have no side effects asPis a number. The"caller"check forPis also skipped, but it would never match becausePis a number.) f. Else, Throw aTypeError. (Note that this case should not happen, as steps a-e are exhaustive. However, this step is useful as a fallback, and for handling any internal types.)
- Let PbeToString(P). (This may have side effects ifPis an object.)
- LOOKUP: If Ois anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments object exotic behavior.) Letmapbe the value of the[[ParameterMap]]internal property of the arguments object. b. If the result of calling the[[GetOwnProperty]]internal method ofmappassingPas the argument is notundefined: 1. Return the result of calling the[[Get]]internal method ofmappassingPas the argument.
- Let descbe the result of calling the[[GetProperty]]internal method ofOwith property nameP.
- If descisundefined, returnundefined.
- If IsDataDescriptor(desc)istrue: a. Letresbedesc.[[Value]].
- Otherwise, IsAccessorDescriptor(desc)must betrue: a. Letgetterbedesc.[[Get]]. b. Ifgetterisundefined, returnundefined. c. Else letresbe the result of calling the[[Call]]internal method ofgetterprovidingorigas thethisvalue and providing no arguments. (Note: the difference to a basic[[Get]]is that the getterthisbinding is the original, uncoerced object.)
- If origis aFunctionobject or anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments or Function object exotic behavior.) IfPis"caller"andresis a strict modeFunctionobject, throw aTypeErrorexception.
- Return res.
We can also move step 4 (arguments exotic behavior) to step 2.e. This has the problem that step 4 assumes P has been string coerced already. So, a duplicate coercion is needed (like for strings):
- Let origbeO. (Remember the uncoerced original for a possible getter call.)
- Check and/or coerce Oas follows: a. IfOisnullorundefined, throw aTypeError. (This is theCheckObjectCoerciblepart; the throw is unconditional.) b. IfOis a boolean: setOto the built-inBooleanprototype object (skip creation of temporary) c. Else ifOis a number: setOto the built-inNumberprototype object (skip creation of temporary) d. Else ifOis a string: 1. IfPis a number, is a whole number, a valid array index, and within the string length, return a one-character substring of the primitive string value at the specified index. (Note:ToString(P)is skipped, but it would have no side effects asPis a number. The"caller"check forPis also skipped, but it would never match becausePis a number.) 2. SetPtoToString(P). (This may have side effects ifPis an object.) 3. IfPislength, return the length of the primitive string value as a number. (Note: The"caller"check forPis skipped, but would never match.) 4. IfPis a valid array index within the string length, return a one-character substring of the primitive string value at the specified index. (Note: The"caller"check forPis skipped, but would never match.) 5. SetOto the built-inStringprototype object (skip creation of temporary) 6. Goto LOOKUP. (Avoid double coercion ofP.) e. Else ifOis an object: 1. Array fast path: IfOis an object (always true here) ANDPis a number and a valid array index (whole number in [0,2**32-2]) ANDOinternal representation has an array part ANDOdoes not have conflicting exotic behaviors (cannot haveStringor arguments exotic behaviors, may haveArraybehavior), then: a. Letidxbe the array index represented byP. b. If the array part ofOcontainsidxand the key exists, read and return that value. (Note:ToString(P)is skipped, but it would have no side effects asPis a number. The"caller"check forPis also skipped, but it would never match becausePis a number.) 2. IfOis anargumentsobject which contains a[[ParameterMap]]internal property: a. SetPtoToString(P). b. (Arguments object exotic behavior.) Letmapbe the value of the[[ParameterMap]]internal property of the arguments object. c. If the result of calling the[[GetOwnProperty]]internal method ofmappassingPas the argument is notundefined: 1. Return the result of calling the[[Get]]internal method ofmappassingPas the argument. d. Else, goto LOOKUP. (Avoid double coercion ofP.) f. Else, Throw aTypeError. (Note that this case should not happen, as steps a-e are exhaustive. However, this step is useful as a fallback, and for handling any internal types.)
- Let PbeToString(P). (This may have side effects ifPis an object.)
- LOOKUP: Let descbe the result of calling the[[GetProperty]]internal method ofOwith property nameP.
- If descisundefined, returnundefined.
- If IsDataDescriptor(desc)istrue: a. Letresbedesc.[[Value]].
- Otherwise, IsAccessorDescriptor(desc)must betrue: a. Letgetterbedesc.[[Get]]. b. Ifgetterisundefined, returnundefined. c. Else letresbe the result of calling the[[Call]]internal method ofgetterprovidingorigas thethisvalue and providing no arguments. (Note: the difference to a basic[[Get]]is that the getterthisbinding is the original, uncoerced object.)
- If origis aFunctionobject or anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments or Function object exotic behavior.) IfPis"caller"andresis a strict modeFunctionobject, throw aTypeErrorexception.
- Return res.
::: note ::: title Note :::
The above is the current "shallow fast path" approach, which has a couple of annoying limitations. For instance, if the array index is not used, the key will be coerced to string (regardless of whether ancestors have the key or not). Many improvements are possible; these are future work. :::
Inlining GetProperty 
Inlining [[GetProperty]] (but not [[GetOwnProperty]]), maintaining the original input value in O instead of orig, and using curr instead of O otherwise, we get:
- Check and/or coerce Oas follows: a. IfOisnullorundefined, throw aTypeError. (This is theCheckObjectCoerciblepart; the throw is unconditional.) b. IfOis a boolean: setcurrto the built-inBooleanprototype object (skip creation of temporary) c. Else ifOis a number: setcurrto the built-inNumberprototype object (skip creation of temporary) d. Else ifOis a string: 1. IfPis a number, is a whole number, a valid array index, and within the string length, return a one-character substring of the primitive string value at the specified index. (Note:ToString(P)is skipped, but it would have no side effects asPis a number. The"caller"check forPis also skipped, but it would never match becausePis a number.) 2. SetPtoToString(P). (This may have side effects ifPis an object.) 3. IfPislength, return the length of the primitive string value as a number. (Note: The"caller"check forPis skipped, but would never match.) 4. IfPis a valid array index within the string length, return a one-character substring of the primitive string value at the specified index. (Note: The"caller"check forPis skipped, but would never match.) 5. Setcurrto the built-inStringprototype object (skip creation of temporary) 6. Goto NEXT. (Avoid double coercion ofP.) e. Else ifOis an object: 1. SetcurrtoO. 2. Array fast path: IfOis an object (always true here) ANDPis a number and a valid array index (whole number in [0,2**32-2]) ANDOinternal representation has an array part ANDOdoes not have conflicting exotic behaviors (cannot haveStringor arguments exotic behaviors, may haveArraybehavior), then: a. Letidxbe the array index represented byP. b. If the array part ofOcontainsidxand the key exists, read and return that value. (Note:ToString(P)is skipped, but it would have no side effects asPis a number. The"caller"check forPis also skipped, but it would never match becausePis a number.) 3. IfOis anargumentsobject which contains a[[ParameterMap]]internal property: a. SetPtoToString(P). b. (Arguments object exotic behavior.) Letmapbe the value of the[[ParameterMap]]internal property of the arguments object. c. If the result of calling the[[GetOwnProperty]]internal method ofmappassingPas the argument is notundefined: 1. Return the result of calling the[[Get]]internal method ofmappassingPas the argument. d. Else, goto NEXT. (Avoid double coercion ofP.) f. Else, Throw aTypeError. (Note that this case should not happen, as steps a-e are exhaustive. However, this step is useful as a fallback, and for handling any internal types.)
- Let PbeToString(P). (This may have side effects ifPis an object.)
- NEXT: Let descbe the result of calling the [[GetOwnProperty]] internal method ofcurrwith property nameP.
- If descisundefined: a. Letcurrbe the value of the[[Prototype]]internal property ofcurr. b. Ifcurris notnull, goto NEXT. c. Returnundefined.
- If IsDataDescriptor(desc)istrue: a. Letresbedesc.[[Value]].
- Otherwise, IsAccessorDescriptor(desc)must betrue: a. Letgetterbedesc.[[Get]]. b. Ifgetterisundefined, returnundefined. c. Else letresbe the result of calling the[[Call]]internal method ofgetterprovidingOas thethisvalue and providing no arguments. (Note: the difference to a basic[[Get]]is that the getterthisbinding is the original, uncoerced object.)
- If Ois aFunctionobject or anargumentsobject which contains a[[ParameterMap]]internal property: a. (Arguments or Function object exotic behavior.) IfPis"caller"andresis a strict modeFunctionobject, throw aTypeErrorexception.
- Return res.
Final version 
(See above.)