All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.mozilla.javascript.Arguments Maven / Gradle / Ivy

Go to download

Rhino is an open-source implementation of JavaScript written entirely in Java. It is typically embedded into Java applications to provide scripting to end users.

There is a newer version: 1.7.15
Show newest version
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import org.mozilla.javascript.NativeArrayIterator.ARRAY_ITERATOR_TYPE;

/**
 * This class implements the "arguments" object.
 *
 * 

See ECMA 10.1.8 * * @see org.mozilla.javascript.NativeCall * @author Norris Boyd */ final class Arguments extends IdScriptableObject { private static final long serialVersionUID = 4275508002492040609L; private static final String FTAG = "Arguments"; public Arguments(NativeCall activation) { this.activation = activation; Scriptable parent = activation.getParentScope(); setParentScope(parent); setPrototype(ScriptableObject.getObjectPrototype(parent)); args = activation.originalArgs; lengthObj = Integer.valueOf(args.length); NativeFunction f = activation.function; calleeObj = f; int version = f.getLanguageVersion(); if (version <= Context.VERSION_1_3 && version != Context.VERSION_DEFAULT) { callerObj = null; } else { callerObj = NOT_FOUND; } defineProperty(SymbolKey.ITERATOR, iteratorMethod, ScriptableObject.DONTENUM); } @Override public String getClassName() { return FTAG; } private Object arg(int index) { if (index < 0 || args.length <= index) return NOT_FOUND; return args[index]; } // the following helper methods assume that 0 < index < args.length private void putIntoActivation(int index, Object value) { String argName = activation.function.getParamOrVarName(index); activation.put(argName, activation, value); } private Object getFromActivation(int index) { String argName = activation.function.getParamOrVarName(index); return activation.get(argName, activation); } private void replaceArg(int index, Object value) { if (sharedWithActivation(index)) { putIntoActivation(index, value); } synchronized (this) { if (args == activation.originalArgs) { args = args.clone(); } args[index] = value; } } private void removeArg(int index) { synchronized (this) { if (args[index] != NOT_FOUND) { if (args == activation.originalArgs) { args = args.clone(); } args[index] = NOT_FOUND; } } } // end helpers @Override public boolean has(int index, Scriptable start) { if (arg(index) != NOT_FOUND) { return true; } return super.has(index, start); } @Override public Object get(int index, Scriptable start) { final Object value = arg(index); if (value == NOT_FOUND) { return super.get(index, start); } if (sharedWithActivation(index)) { return getFromActivation(index); } return value; } private boolean sharedWithActivation(int index) { Context cx = Context.getContext(); if (cx.isStrictMode()) { return false; } NativeFunction f = activation.function; int definedCount = f.getParamCount(); if (index < definedCount) { // Check if argument is not hidden by later argument with the same // name as hidden arguments are not shared with activation if (index < definedCount - 1) { String argName = f.getParamOrVarName(index); for (int i = index + 1; i < definedCount; i++) { if (argName.equals(f.getParamOrVarName(i))) { return false; } } } return true; } return false; } @Override public void put(int index, Scriptable start, Object value) { if (arg(index) == NOT_FOUND) { super.put(index, start, value); } else { replaceArg(index, value); } } @Override public void put(String name, Scriptable start, Object value) { super.put(name, start, value); } @Override public void delete(int index) { if (0 <= index && index < args.length) { removeArg(index); } super.delete(index); } private static final int Id_callee = 1, Id_length = 2, Id_caller = 3, MAX_INSTANCE_ID = Id_caller; @Override protected int getMaxInstanceId() { return MAX_INSTANCE_ID; } @Override protected int findInstanceIdInfo(String s) { int id; switch (s) { case "callee": id = Id_callee; break; case "length": id = Id_length; break; case "caller": id = Id_caller; break; default: id = 0; break; } Context cx = Context.getContext(); if (cx.isStrictMode()) { if (id == Id_callee || id == Id_caller) { return super.findInstanceIdInfo(s); } } if (id == 0) return super.findInstanceIdInfo(s); int attr; switch (id) { case Id_callee: attr = calleeAttr; break; case Id_caller: attr = callerAttr; break; case Id_length: attr = lengthAttr; break; default: throw new IllegalStateException(); } return instanceIdInfo(attr, id); } @Override protected String getInstanceIdName(int id) { switch (id) { case Id_callee: return "callee"; case Id_length: return "length"; case Id_caller: return "caller"; } return null; } @Override protected Object getInstanceIdValue(int id) { switch (id) { case Id_callee: return calleeObj; case Id_length: return lengthObj; case Id_caller: { Object value = callerObj; if (value == UniqueTag.NULL_VALUE) { value = null; } else if (value == null) { NativeCall caller = activation.parentActivationCall; if (caller != null) { value = caller.get("arguments", caller); } } return value; } } return super.getInstanceIdValue(id); } @Override protected void setInstanceIdValue(int id, Object value) { switch (id) { case Id_callee: calleeObj = value; return; case Id_length: lengthObj = value; return; case Id_caller: callerObj = (value != null) ? value : UniqueTag.NULL_VALUE; return; } super.setInstanceIdValue(id, value); } @Override protected void setInstanceIdAttributes(int id, int attr) { switch (id) { case Id_callee: calleeAttr = attr; return; case Id_length: lengthAttr = attr; return; case Id_caller: callerAttr = attr; return; } super.setInstanceIdAttributes(id, attr); } @Override Object[] getIds(boolean getNonEnumerable, boolean getSymbols) { Object[] ids = super.getIds(getNonEnumerable, getSymbols); if (args.length != 0) { boolean[] present = new boolean[args.length]; int extraCount = args.length; for (int i = 0; i != ids.length; ++i) { Object id = ids[i]; if (id instanceof Integer) { int index = ((Integer) id).intValue(); if (0 <= index && index < args.length) { if (!present[index]) { present[index] = true; extraCount--; } } } } if (!getNonEnumerable) { // avoid adding args which were redefined to non-enumerable for (int i = 0; i < present.length; i++) { if (!present[i] && super.has(i, this)) { present[i] = true; extraCount--; } } } if (extraCount != 0) { Object[] tmp = new Object[extraCount + ids.length]; System.arraycopy(ids, 0, tmp, extraCount, ids.length); ids = tmp; int offset = 0; for (int i = 0; i != args.length; ++i) { if (!present[i]) { ids[offset] = Integer.valueOf(i); ++offset; } } if (offset != extraCount) Kit.codeBug(); } } return ids; } @Override protected ScriptableObject getOwnPropertyDescriptor(Context cx, Object id) { if (ScriptRuntime.isSymbol(id) || id instanceof Scriptable) { return super.getOwnPropertyDescriptor(cx, id); } double d = ScriptRuntime.toNumber(id); int index = (int) d; if (d != index) { return super.getOwnPropertyDescriptor(cx, id); } Object value = arg(index); if (value == NOT_FOUND) { return super.getOwnPropertyDescriptor(cx, id); } if (sharedWithActivation(index)) { value = getFromActivation(index); } if (super.has(index, this)) { // the descriptor has been redefined ScriptableObject desc = super.getOwnPropertyDescriptor(cx, id); desc.put("value", desc, value); return desc; } Scriptable scope = getParentScope(); if (scope == null) scope = this; return buildDataDescriptor(scope, value, EMPTY); } @Override protected void defineOwnProperty( Context cx, Object id, ScriptableObject desc, boolean checkValid) { super.defineOwnProperty(cx, id, desc, checkValid); if (ScriptRuntime.isSymbol(id)) { return; } double d = ScriptRuntime.toNumber(id); int index = (int) d; if (d != index) return; Object value = arg(index); if (value == NOT_FOUND) return; if (isAccessorDescriptor(desc)) { removeArg(index); return; } Object newValue = getProperty(desc, "value"); if (newValue == NOT_FOUND) return; replaceArg(index, newValue); if (isFalse(getProperty(desc, "writable"))) { removeArg(index); } } // ECMAScript2015 // 9.4.4.6 CreateUnmappedArgumentsObject(argumentsList) // 8. Perform DefinePropertyOrThrow(obj, "caller", PropertyDescriptor {[[Get]]: // %ThrowTypeError%, // [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false}). // 9. Perform DefinePropertyOrThrow(obj, "callee", PropertyDescriptor {[[Get]]: // %ThrowTypeError%, // [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false}). void defineAttributesForStrictMode() { Context cx = Context.getContext(); if (!cx.isStrictMode()) { return; } setGetterOrSetter("caller", 0, new ThrowTypeError("caller"), true); setGetterOrSetter("caller", 0, new ThrowTypeError("caller"), false); setGetterOrSetter("callee", 0, new ThrowTypeError("callee"), true); setGetterOrSetter("callee", 0, new ThrowTypeError("callee"), false); setAttributes("caller", DONTENUM | PERMANENT); setAttributes("callee", DONTENUM | PERMANENT); callerObj = null; calleeObj = null; } private static BaseFunction iteratorMethod = new BaseFunction() { private static final long serialVersionUID = 4239122318596177391L; @Override public Object call( Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { // TODO : call %ArrayProto_values% // 9.4.4.6 CreateUnmappedArgumentsObject(argumentsList) // 1. Perform DefinePropertyOrThrow(obj, @@iterator, PropertyDescriptor // {[[Value]]:%ArrayProto_values%, // [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}). return new NativeArrayIterator(scope, thisObj, ARRAY_ITERATOR_TYPE.VALUES); } }; private static class ThrowTypeError extends BaseFunction { private static final long serialVersionUID = -744615873947395749L; private String propertyName; ThrowTypeError(String propertyName) { this.propertyName = propertyName; } @Override public Object call(Context cx, Scriptable scope, Scriptable thisObj, Object[] args) { throw ScriptRuntime.typeErrorById("msg.arguments.not.access.strict", propertyName); } } // Fields to hold caller, callee and length properties, // where NOT_FOUND value tags deleted properties. // In addition if callerObj == NULL_VALUE, it tags null for scripts, as // initial callerObj == null means access to caller arguments available // only in JS <= 1.3 scripts private Object callerObj; private Object calleeObj; private Object lengthObj; private int callerAttr = DONTENUM; private int calleeAttr = DONTENUM; private int lengthAttr = DONTENUM; private NativeCall activation; // Initially args holds activation.getOriginalArgs(), but any modification // of its elements triggers creation of a copy. If its element holds NOT_FOUND, // it indicates deleted index, in which case super class is queried. private Object[] args; }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy