/** * ECMA 15.4.4.4 Array.prototype.concat ( [ item1 [ , item2 [ , ... ] ] ] ) * * @param self self reference * @param arg argument * @return resulting NativeArray */ @SpecializedFunction(linkLogic=ConcatLinkLogic.class) public static NativeArray concat(final Object self, final Object arg) { //arg is [NativeArray] of same type. final ContinuousArrayData selfData = getContinuousArrayDataCCE(self); final ContinuousArrayData newData; if (arg instanceof NativeArray) { final ContinuousArrayData argData = (ContinuousArrayData)((NativeArray)arg).getArray(); if (argData.isEmpty()) { newData = selfData.copy(); } else if (selfData.isEmpty()) { newData = argData.copy(); } else { final Class<?> widestElementType = selfData.widest(argData).getBoxedElementType(); newData = ((ContinuousArrayData)selfData.convert(widestElementType)).fastConcat((ContinuousArrayData)argData.convert(widestElementType)); } } else { newData = getContinuousArrayDataCCE(self, Object.class).copy(); newData.fastPush(arg); } return new NativeArray(newData); }
@Override public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { final Object[] args = request.getArguments(); if (args.length != 3) { //single argument check return false; } final ContinuousArrayData selfData = getContinuousArrayData(self); if (selfData == null) { return false; } final Object arg = args[2]; //args[2] continuousarray or non arraydata, let past non array datas if (arg instanceof NativeArray) { final ContinuousArrayData argData = getContinuousArrayData(arg); if (argData == null) { return false; } } return true; }
@Override public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { final Object[] args = request.getArguments(); if (args.length != 3) { //single argument check return false; } final ContinuousArrayData selfData = getContinuousArrayData(self); if (selfData == null) { return false; } final Object arg = args[2]; // The generic version uses its own logic and ArrayLikeIterator to decide if an object should // be iterated over or added as single element. To avoid duplication of code and err on the safe side // we only use the specialized version if arg is either a continuous array or a JS primitive. if (arg instanceof NativeArray) { return (getContinuousArrayData(arg) != null); } return JSType.isPrimitive(arg); }
protected static ContinuousArrayData getContinuousArrayData(final Object self) { try { //cast to NativeArray, to avoid cases like x = {0:0, 1:1}, x.length = 2, where we can't use the array push/pop return (ContinuousArrayData)((NativeArray)self).getArray(); } catch (final Exception e) { return null; } }
/** * We need to check if we are dealing with a continuous non empty array data here, * as pop with a primitive return value returns undefined for arrays with length 0 */ @Override public boolean canLink(final Object self, final CallSiteDescriptor desc, final LinkRequest request) { final ContinuousArrayData data = getContinuousNonEmptyArrayData(self); if (data != null) { final Class<?> elementType = data.getElementType(); final Class<?> returnType = desc.getMethodType().returnType(); final boolean typeFits = JSType.getAccessorTypeIndex(returnType) >= JSType.getAccessorTypeIndex(elementType); return typeFits; } return false; }
private static ContinuousArrayData getContinuousNonEmptyArrayData(final Object self) { final ContinuousArrayData data = getContinuousArrayData(self); if (data != null) { return data.length() == 0 ? null : data; } return null; }
private static final <T> ContinuousArrayData getContinuousNonEmptyArrayDataCCE(final Object self, final Class<T> clazz) { try { @SuppressWarnings("unchecked") final ContinuousArrayData data = (ContinuousArrayData)(T)((NativeArray)self).getArray(); if (data.length() != 0L) { return data; //if length is 0 we cannot pop and have to relink, because then we'd have to return an undefined, which is a wider type than e.g. int } } catch (final NullPointerException e) { //fallthru } throw new ClassCastException(); }
private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self) { try { return (ContinuousArrayData)((NativeArray)self).getArray(); } catch (final NullPointerException e) { throw new ClassCastException(); } }
private static final ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) { try { return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType" } catch (final NullPointerException e) { throw new ClassCastException(); } }
private static <T> ContinuousArrayData getContinuousNonEmptyArrayDataCCE(final Object self, final Class<T> clazz) { try { @SuppressWarnings("unchecked") final ContinuousArrayData data = (ContinuousArrayData)(T)((NativeArray)self).getArray(); if (data.length() != 0L) { return data; //if length is 0 we cannot pop and have to relink, because then we'd have to return an undefined, which is a wider type than e.g. int } } catch (final NullPointerException e) { //fallthru } throw new ClassCastException(); }
private static ContinuousArrayData getContinuousArrayDataCCE(final Object self) { try { return (ContinuousArrayData)((NativeArray)self).getArray(); } catch (final NullPointerException e) { throw new ClassCastException(); } }
private static ContinuousArrayData getContinuousArrayDataCCE(final Object self, final Class<?> elementType) { try { return (ContinuousArrayData)((NativeArray)self).getArray(elementType); //ensure element type can fit "elementType" } catch (final NullPointerException e) { throw new ClassCastException(); } }