@Override public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { if (lexicalScope.hasOwnProperty(name)) { return lexicalScope.findGetMethod(desc, request, operator); } } final GuardedInvocation invocation = super.findGetMethod(desc, request, operator); // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, // because those are invalidated per-key in the addBoundProperties method above. // We therefor check if the invocation does already have a switchpoint and the property is non-inherited, // assuming this only applies to global constants. If other non-inherited properties will // start using switchpoints some time in the future we'll have to revisit this. if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); } return invocation; }
@Override public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope) { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); if (lexicalScope.hasOwnProperty(name)) { return lexicalScope.findSetMethod(desc, request); } } final GuardedInvocation invocation = super.findSetMethod(desc, request); if (isScope && context.getEnv()._es6) { return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); } return invocation; }
/** * Return a fast linked array getter, or null if we have to dispatch to super class * @param desc descriptor * @param request link request * @return invocation or null if needs to be sent to slow relink */ @Override public GuardedInvocation findFastGetIndexMethod(final Class<? extends ArrayData> clazz, final CallSiteDescriptor desc, final LinkRequest request) { final MethodType callType = desc.getMethodType(); final Class<?> indexType = callType.parameterType(1); final Class<?> returnType = callType.returnType(); if (ContinuousArrayData.class.isAssignableFrom(clazz) && indexType == int.class) { final Object[] args = request.getArguments(); final int index = (int)args[args.length - 1]; if (has(index)) { final MethodHandle getArray = ScriptObject.GET_ARRAY.methodHandle(); final int programPoint = NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT; MethodHandle getElement = getElementGetter(returnType, programPoint); if (getElement != null) { getElement = MH.filterArguments(getElement, 0, MH.asType(getArray, getArray.type().changeReturnType(clazz))); final MethodHandle guard = MH.insertArguments(FAST_ACCESS_GUARD, 0, clazz); return new GuardedInvocation(getElement, guard, (SwitchPoint)null, ClassCastException.class); } } } return null; }
@Override public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request) { final String name = NashornCallSiteDescriptor.getOperand(desc); final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { if (lexicalScope.hasOwnProperty(name)) { return lexicalScope.findGetMethod(desc, request); } } final GuardedInvocation invocation = super.findGetMethod(desc, request); // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, // because those are invalidated per-key in the addBoundProperties method above. // We therefore check if the invocation does already have a switchpoint and the property is non-inherited, // assuming this only applies to global constants. If other non-inherited properties will // start using switchpoints some time in the future we'll have to revisit this. if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); } return invocation; }
@Override public GuardedInvocation findSetMethod(final CallSiteDescriptor desc, final LinkRequest request) { final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope) { final String name = NashornCallSiteDescriptor.getOperand(desc); if (lexicalScope.hasOwnProperty(name)) { return lexicalScope.findSetMethod(desc, request); } } final GuardedInvocation invocation = super.findSetMethod(desc, request); if (isScope && context.getEnv()._es6) { return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); } return invocation; }
/** * Lookup the appropriate method for an invoke dynamic call. * @param desc The invoke dynamic callsite descriptor. * @return GuardedInvocation to be invoked at call site. */ public static GuardedInvocation lookup(final CallSiteDescriptor desc) { switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { case CALL: case NEW: final String name = NashornCallSiteDescriptor.getOperand(desc); final String msg = name != null? "not.a.function" : "cant.call.undefined"; throw typeError(msg, name); case GET: // NOTE: we support GET:ELEMENT and SET:ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself // emits "GET:PROPERTY|ELEMENT|METHOD:identifier" for "<expr>.<identifier>" and "GET:ELEMENT|PROPERTY|METHOD" for "<expr>[<expr>]", but we are // more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the // operation has an associated name or not. if (!(desc.getOperation() instanceof NamedOperation)) { return findGetIndexMethod(desc); } return findGetMethod(desc); case SET: if (!(desc.getOperation() instanceof NamedOperation)) { return findSetIndexMethod(desc); } return findSetMethod(desc); default: } return null; }
/** * Lookup method that, given a CallSiteDescriptor, looks up the target * MethodHandle and creates a GuardedInvocation * with the appropriate guard(s). * * @param desc call site descriptor * @param request the link request * * @return GuardedInvocation for the callsite */ public GuardedInvocation lookup(final CallSiteDescriptor desc, final LinkRequest request) { // NOTE: we support GET:ELEMENT and SET:ELEMENT as JavaScript doesn't distinguish items from properties. Nashorn itself // emits "GET:PROPERTY|ELEMENT|METHOD:identifier" for "<expr>.<identifier>" and "GET:ELEMENT|PROPERTY|METHOD" for "<expr>[<expr>]", but we are // more flexible here and dispatch not on operation name (getProp vs. getElem), but rather on whether the // operation has an associated name or not. switch (NashornCallSiteDescriptor.getStandardOperation(desc)) { case GET: return desc.getOperation() instanceof NamedOperation ? findGetMethod(desc, request) : findGetIndexMethod(desc, request); case SET: return desc.getOperation() instanceof NamedOperation ? findSetMethod(desc, request) : findSetIndexMethod(desc, request); case CALL: return findCallMethod(desc, request); case NEW: return findNewMethod(desc, request); default: return null; } }
@Override public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final StandardOperation operation) { final String name = NashornCallSiteDescriptor.getOperand(desc); final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { if (lexicalScope.hasOwnProperty(name)) { return lexicalScope.findGetMethod(desc, request, operation); } } final GuardedInvocation invocation = super.findGetMethod(desc, request, operation); // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, // because those are invalidated per-key in the addBoundProperties method above. // We therefore check if the invocation does already have a switchpoint and the property is non-inherited, // assuming this only applies to global constants. If other non-inherited properties will // start using switchpoints some time in the future we'll have to revisit this. if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); } return invocation; }
@Override public GuardedInvocation findGetMethod(final CallSiteDescriptor desc, final LinkRequest request, final String operator) { final String name = desc.getNameToken(CallSiteDescriptor.NAME_OPERAND); final boolean isScope = NashornCallSiteDescriptor.isScope(desc); if (lexicalScope != null && isScope && !NashornCallSiteDescriptor.isApplyToCall(desc)) { if (lexicalScope.hasOwnProperty(name)) { return lexicalScope.findGetMethod(desc, request, operator); } } final GuardedInvocation invocation = super.findGetMethod(desc, request, operator); // We want to avoid adding our generic lexical scope switchpoint to global constant invocations, // because those are invalidated per-key in the addBoundProperties method above. // We therefore check if the invocation does already have a switchpoint and the property is non-inherited, // assuming this only applies to global constants. If other non-inherited properties will // start using switchpoints some time in the future we'll have to revisit this. if (isScope && context.getEnv()._es6 && (invocation.getSwitchPoints() == null || !hasOwnProperty(name))) { return invocation.addSwitchPoint(getLexicalScopeSwitchPoint()); } return invocation; }
@SuppressWarnings("unused") private static void setSpillWithNew(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final Object self, final Object value) { final ScriptObject obj = (ScriptObject)self; final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc); if (!obj.isExtensible()) { if (isStrict) { throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj)); } } else if (obj.compareAndSetMap(oldMap, newMap)) { obj.spill = new Object[SPILL_RATE]; obj.spill[index] = value; } else { obj.set(desc.getNameToken(2), value, isStrict); } }
@SuppressWarnings("unused") private static void setSpillWithGrow(final CallSiteDescriptor desc, final PropertyMap oldMap, final PropertyMap newMap, final int index, final int newLength, final Object self, final Object value) { final ScriptObject obj = (ScriptObject)self; final boolean isStrict = NashornCallSiteDescriptor.isStrict(desc); if (!obj.isExtensible()) { if (isStrict) { throw typeError("object.non.extensible", desc.getNameToken(2), ScriptRuntime.safeToString(obj)); } } else if (obj.compareAndSetMap(oldMap, newMap)) { final int oldLength = obj.spill.length; final Object[] newSpill = new Object[newLength]; System.arraycopy(obj.spill, 0, newSpill, 0, oldLength); obj.spill = newSpill; obj.spill[index] = value; } else { obj.set(desc.getNameToken(2), value, isStrict); } }
/** * Fall back if a function property is not found. * @param desc The call site descriptor * @param request the link request * @return GuardedInvocation to be invoked at call site. */ public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) { final String name = desc.getNameToken(2); final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true); final boolean scopeCall = isScope() && NashornCallSiteDescriptor.isScope(desc); if (find == null) { return noSuchProperty(desc, request); } final Object value = getObjectValue(find); if (! (value instanceof ScriptFunction)) { return createEmptyGetter(desc, name); } final ScriptFunction func = (ScriptFunction)value; final Object thiz = scopeCall && func.isStrict() ? ScriptRuntime.UNDEFINED : this; // TODO: It'd be awesome if we could bind "name" without binding "this". return new GuardedInvocation(MH.dropArguments(MH.constant(ScriptFunction.class, func.makeBoundFunction(thiz, new Object[] { name })), 0, Object.class), null, NashornGuards.getMapGuard(getMap())); }
private static GuardedInvocation fixExpressionCallSite(final NashornCallSiteDescriptor desc, final GuardedInvocation link) { // If it's not a getMethod, just add an expression filter that converts WithObject in "this" position to its // expression. if(!"getMethod".equals(desc.getFirstOperator())) { return fixReceiverType(link, WITHEXPRESSIONFILTER).filterArguments(0, WITHEXPRESSIONFILTER); } final MethodHandle linkInvocation = link.getInvocation(); final MethodType linkType = linkInvocation.type(); final boolean linkReturnsFunction = ScriptFunction.class.isAssignableFrom(linkType.returnType()); return link.replaceMethods( // Make sure getMethod will bind the script functions it receives to WithObject.expression MH.foldArguments(linkReturnsFunction ? BIND_TO_EXPRESSION_FN : BIND_TO_EXPRESSION_OBJ, filter(linkInvocation.asType(linkType.changeReturnType( linkReturnsFunction ? ScriptFunction.class : Object.class)), WITHEXPRESSIONFILTER)), // No clever things for the guard -- it is still identically filtered. filterGuard(link, WITHEXPRESSIONFILTER)); }
@SuppressWarnings("unchecked") private static LinkedList<RuntimeEvent<?>> getEventQueue(final Object self) { final ScriptObject sobj = (ScriptObject)self; LinkedList<RuntimeEvent<?>> q; if (sobj.has(EVENT_QUEUE)) { q = (LinkedList<RuntimeEvent<?>>)((ScriptObject)self).get(EVENT_QUEUE); } else { ((ScriptObject)self).set(EVENT_QUEUE, q = new LinkedList<>(), NashornCallSiteDescriptor.CALLSITE_STRICT); } return q; }
/** * Given a guarded invocation and a callsite descriptor, perform return value filtering * according to the optimistic type coercion rules, using the return value from the descriptor * @param inv the invocation * @param desc the descriptor * @return filtered invocation */ public static GuardedInvocation filterOptimisticReturnValue(final GuardedInvocation inv, final CallSiteDescriptor desc) { if(!NashornCallSiteDescriptor.isOptimistic(desc)) { return inv; } return inv.replaceMethods(filterOptimisticReturnValue(inv.getInvocation(), desc.getMethodType().returnType(), NashornCallSiteDescriptor.getProgramPoint(desc)), inv.getGuard()); }
/** * Find a handle for a getIndex method * @param returnType return type for getter * @param name name * @param elementType index type for getter * @param desc call site descriptor * @return method handle for getter */ protected MethodHandle findGetIndexMethodHandle(final Class<?> returnType, final String name, final Class<?> elementType, final CallSiteDescriptor desc) { if (!returnType.isPrimitive()) { return findOwnMH_V(getClass(), name, returnType, elementType); } return MH.insertArguments( findOwnMH_V(getClass(), name, returnType, elementType, int.class), 2, NashornCallSiteDescriptor.isOptimistic(desc) ? NashornCallSiteDescriptor.getProgramPoint(desc) : INVALID_PROGRAM_POINT); }
/** * Fall back if a function property is not found. * @param desc The call site descriptor * @param request the link request * @return GuardedInvocation to be invoked at call site. */ public GuardedInvocation noSuchMethod(final CallSiteDescriptor desc, final LinkRequest request) { final String name = desc.getNameToken(2); final FindProperty find = findProperty(NO_SUCH_METHOD_NAME, true); final boolean scopeCall = isScope() && NashornCallSiteDescriptor.isScope(desc); if (find == null) { return noSuchProperty(desc, request); } final boolean explicitInstanceOfCheck = explicitInstanceOfCheck(desc, request); final Object value = find.getObjectValue(); if (!(value instanceof ScriptFunction)) { return createEmptyGetter(desc, explicitInstanceOfCheck, name); } final ScriptFunction func = (ScriptFunction)value; final Object thiz = scopeCall && func.isStrict() ? UNDEFINED : this; // TODO: It'd be awesome if we could bind "name" without binding "this". // Since we're binding this we must use an identity guard here. return new GuardedInvocation( MH.dropArguments( MH.constant( ScriptFunction.class, func.makeBoundFunction(thiz, new Object[] { name })), 0, Object.class), NashornGuards.combineGuards( NashornGuards.getIdentityGuard(this), NashornGuards.getMapGuard(getMap(), true))); }
private GuardedInvocation createEmptyGetter(final CallSiteDescriptor desc, final boolean explicitInstanceOfCheck, final String name) { if (NashornCallSiteDescriptor.isOptimistic(desc)) { throw new UnwarrantedOptimismException(UNDEFINED, NashornCallSiteDescriptor.getProgramPoint(desc), Type.OBJECT); } return new GuardedInvocation(Lookup.emptyGetter(desc.getMethodType().returnType()), NashornGuards.getMapGuard(getMap(), explicitInstanceOfCheck), getProtoSwitchPoint(name, null), explicitInstanceOfCheck ? null : ClassCastException.class); }