001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002: *
003: * ***** BEGIN LICENSE BLOCK *****
004: * Version: MPL 1.1/GPL 2.0
005: *
006: * The contents of this file are subject to the Mozilla Public License Version
007: * 1.1 (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: * http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the
014: * License.
015: *
016: * The Original Code is Rhino code, released
017: * May 6, 1999.
018: *
019: * The Initial Developer of the Original Code is
020: * Netscape Communications Corporation.
021: * Portions created by the Initial Developer are Copyright (C) 1997-1999
022: * the Initial Developer. All Rights Reserved.
023: *
024: * Contributor(s):
025: * Norris Boyd
026: * Igor Bukanov
027: *
028: * Alternatively, the contents of this file may be used under the terms of
029: * the GNU General Public License Version 2 or later (the "GPL"), in which
030: * case the provisions of the GPL are applicable instead of those above. If
031: * you wish to allow use of your version of this file only under the terms of
032: * the GPL and not to allow others to use your version of this file under the
033: * MPL, indicate your decision by deleting the provisions above and replacing
034: * them with the notice and other provisions required by the GPL. If you do
035: * not delete the provisions above, a recipient may use your version of this
036: * file under either the MPL or the GPL.
037: *
038: * ***** END LICENSE BLOCK ***** */
039:
040: package org.mozilla.javascript;
041:
042: /**
043: * This class implements the "arguments" object.
044: *
045: * See ECMA 10.1.8
046: *
047: * @see org.mozilla.javascript.NativeCall
048: * @author Norris Boyd
049: */
050: final class Arguments extends IdScriptableObject {
051: static final long serialVersionUID = 4275508002492040609L;
052:
053: public Arguments(NativeCall activation) {
054: this .activation = activation;
055:
056: Scriptable parent = activation.getParentScope();
057: setParentScope(parent);
058: setPrototype(ScriptableObject.getObjectPrototype(parent));
059:
060: args = activation.originalArgs;
061: lengthObj = new Integer(args.length);
062:
063: NativeFunction f = activation.function;
064: calleeObj = f;
065:
066: int version = f.getLanguageVersion();
067: if (version <= Context.VERSION_1_3
068: && version != Context.VERSION_DEFAULT) {
069: callerObj = null;
070: } else {
071: callerObj = NOT_FOUND;
072: }
073: }
074:
075: public String getClassName() {
076: return "Object";
077: }
078:
079: public boolean has(int index, Scriptable start) {
080: if (0 <= index && index < args.length) {
081: if (args[index] != NOT_FOUND) {
082: return true;
083: }
084: }
085: return super .has(index, start);
086: }
087:
088: public Object get(int index, Scriptable start) {
089: if (0 <= index && index < args.length) {
090: Object value = args[index];
091: if (value != NOT_FOUND) {
092: if (sharedWithActivation(index)) {
093: NativeFunction f = activation.function;
094: String argName = f.getParamOrVarName(index);
095: value = activation.get(argName, activation);
096: if (value == NOT_FOUND)
097: Kit.codeBug();
098: }
099: return value;
100: }
101: }
102: return super .get(index, start);
103: }
104:
105: private boolean sharedWithActivation(int index) {
106: NativeFunction f = activation.function;
107: int definedCount = f.getParamCount();
108: if (index < definedCount) {
109: // Check if argument is not hidden by later argument with the same
110: // name as hidden arguments are not shared with activation
111: if (index < definedCount - 1) {
112: String argName = f.getParamOrVarName(index);
113: for (int i = index + 1; i < definedCount; i++) {
114: if (argName.equals(f.getParamOrVarName(i))) {
115: return false;
116: }
117: }
118: }
119: return true;
120: }
121: return false;
122: }
123:
124: public void put(int index, Scriptable start, Object value) {
125: if (0 <= index && index < args.length) {
126: if (args[index] != NOT_FOUND) {
127: if (sharedWithActivation(index)) {
128: String argName;
129: argName = activation.function
130: .getParamOrVarName(index);
131: activation.put(argName, activation, value);
132: return;
133: }
134: synchronized (this ) {
135: if (args[index] != NOT_FOUND) {
136: if (args == activation.originalArgs) {
137: args = args.clone();
138: }
139: args[index] = value;
140: return;
141: }
142: }
143: }
144: }
145: super .put(index, start, value);
146: }
147:
148: public void delete(int index) {
149: if (0 <= index && index < args.length) {
150: synchronized (this ) {
151: if (args[index] != NOT_FOUND) {
152: if (args == activation.originalArgs) {
153: args = args.clone();
154: }
155: args[index] = NOT_FOUND;
156: return;
157: }
158: }
159: }
160: super .delete(index);
161: }
162:
163: // #string_id_map#
164:
165: private static final int Id_callee = 1, Id_length = 2,
166: Id_caller = 3,
167:
168: MAX_INSTANCE_ID = 3;
169:
170: protected int getMaxInstanceId() {
171: return MAX_INSTANCE_ID;
172: }
173:
174: protected int findInstanceIdInfo(String s) {
175: int id;
176: // #generated# Last update: 2007-05-09 08:15:04 EDT
177: L0: {
178: id = 0;
179: String X = null;
180: int c;
181: if (s.length() == 6) {
182: c = s.charAt(5);
183: if (c == 'e') {
184: X = "callee";
185: id = Id_callee;
186: } else if (c == 'h') {
187: X = "length";
188: id = Id_length;
189: } else if (c == 'r') {
190: X = "caller";
191: id = Id_caller;
192: }
193: }
194: if (X != null && X != s && !X.equals(s))
195: id = 0;
196: break L0;
197: }
198: // #/generated#
199:
200: if (id == 0)
201: return super .findInstanceIdInfo(s);
202:
203: int attr;
204: switch (id) {
205: case Id_callee:
206: case Id_caller:
207: case Id_length:
208: attr = DONTENUM;
209: break;
210: default:
211: throw new IllegalStateException();
212: }
213: return instanceIdInfo(attr, id);
214: }
215:
216: // #/string_id_map#
217:
218: protected String getInstanceIdName(int id) {
219: switch (id) {
220: case Id_callee:
221: return "callee";
222: case Id_length:
223: return "length";
224: case Id_caller:
225: return "caller";
226: }
227: return null;
228: }
229:
230: protected Object getInstanceIdValue(int id) {
231: switch (id) {
232: case Id_callee:
233: return calleeObj;
234: case Id_length:
235: return lengthObj;
236: case Id_caller: {
237: Object value = callerObj;
238: if (value == UniqueTag.NULL_VALUE) {
239: value = null;
240: } else if (value == null) {
241: NativeCall caller = activation.parentActivationCall;
242: if (caller != null) {
243: value = caller.get("arguments", caller);
244: }
245: }
246: return value;
247: }
248: }
249: return super .getInstanceIdValue(id);
250: }
251:
252: protected void setInstanceIdValue(int id, Object value) {
253: switch (id) {
254: case Id_callee:
255: calleeObj = value;
256: return;
257: case Id_length:
258: lengthObj = value;
259: return;
260: case Id_caller:
261: callerObj = (value != null) ? value : UniqueTag.NULL_VALUE;
262: return;
263: }
264: super .setInstanceIdValue(id, value);
265: }
266:
267: Object[] getIds(boolean getAll) {
268: Object[] ids = super .getIds(getAll);
269: if (getAll && args.length != 0) {
270: boolean[] present = null;
271: int extraCount = args.length;
272: for (int i = 0; i != ids.length; ++i) {
273: Object id = ids[i];
274: if (id instanceof Integer) {
275: int index = ((Integer) id).intValue();
276: if (0 <= index && index < args.length) {
277: if (present == null) {
278: present = new boolean[args.length];
279: }
280: if (!present[index]) {
281: present[index] = true;
282: extraCount--;
283: }
284: }
285: }
286: }
287: if (extraCount != 0) {
288: Object[] tmp = new Object[extraCount + ids.length];
289: System.arraycopy(ids, 0, tmp, extraCount, ids.length);
290: ids = tmp;
291: int offset = 0;
292: for (int i = 0; i != args.length; ++i) {
293: if (present == null || !present[i]) {
294: ids[offset] = new Integer(i);
295: ++offset;
296: }
297: }
298: if (offset != extraCount)
299: Kit.codeBug();
300: }
301: }
302: return ids;
303: }
304:
305: // Fields to hold caller, callee and length properties,
306: // where NOT_FOUND value tags deleted properties.
307: // In addition if callerObj == NULL_VALUE, it tags null for scripts, as
308: // initial callerObj == null means access to caller arguments available
309: // only in JS <= 1.3 scripts
310: private Object callerObj;
311: private Object calleeObj;
312: private Object lengthObj;
313:
314: private NativeCall activation;
315:
316: // Initially args holds activation.getOriginalArgs(), but any modification
317: // of its elements triggers creation of a copy. If its element holds NOT_FOUND,
318: // it indicates deleted index, in which case super class is queried.
319: private Object[] args;
320: }
|