/**
* Copyright (c) 2012-2016 André Bargull
* Alle Rechte vorbehalten / All Rights Reserved. Use is subject to license terms.
*
* <https://github.com/anba/es6draft>
*/
package com.github.anba.es6draft.runtime.objects.atomics;
import static com.github.anba.es6draft.runtime.AbstractOperations.ToLength;
import static com.github.anba.es6draft.runtime.AbstractOperations.ToNumber;
import static com.github.anba.es6draft.runtime.internal.Errors.newRangeError;
import static com.github.anba.es6draft.runtime.internal.Errors.newTypeError;
import static com.github.anba.es6draft.runtime.internal.Properties.createProperties;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import com.github.anba.es6draft.runtime.ExecutionContext;
import com.github.anba.es6draft.runtime.Realm;
import com.github.anba.es6draft.runtime.internal.Initializable;
import com.github.anba.es6draft.runtime.internal.Messages;
import com.github.anba.es6draft.runtime.internal.Properties.Accessor;
import com.github.anba.es6draft.runtime.internal.Properties.Attributes;
import com.github.anba.es6draft.runtime.internal.Properties.Function;
import com.github.anba.es6draft.runtime.internal.Properties.Prototype;
import com.github.anba.es6draft.runtime.internal.Properties.Value;
import com.github.anba.es6draft.runtime.objects.binary.ArrayBuffer;
import com.github.anba.es6draft.runtime.objects.binary.ArrayBufferView;
import com.github.anba.es6draft.runtime.types.BuiltinSymbol;
import com.github.anba.es6draft.runtime.types.Constructor;
import com.github.anba.es6draft.runtime.types.Intrinsics;
import com.github.anba.es6draft.runtime.types.ScriptObject;
import com.github.anba.es6draft.runtime.types.builtins.BuiltinConstructor;
/**
* <h1>Shared Memory and Atomics</h1><br>
* <h2>SharedArrayBuffer Objects</h2>
* <ul>
* <li>Abstract Operations For SharedArrayBuffer Objects
* <li>The SharedArrayBuffer Constructor
* <li>Properties of the SharedArrayBuffer Constructor
* </ul>
*/
public final class SharedArrayBufferConstructor extends BuiltinConstructor implements Initializable {
/**
* Constructs a new SharedArrayBuffer constructor function.
*
* @param realm
* the realm object
*/
public SharedArrayBufferConstructor(Realm realm) {
super(realm, "SharedArrayBuffer", 1);
}
@Override
public void initialize(Realm realm) {
createProperties(realm, this, Properties.class);
}
@Override
public SharedArrayBufferConstructor clone() {
return new SharedArrayBufferConstructor(getRealm());
}
/**
* CreateSharedByteDataBlock( size )
*
* @param cx
* the execution context
* @param size
* the byte buffer size in bytes
* @return the new byte buffer
*/
public static ByteBuffer CreateSharedByteDataBlock(ExecutionContext cx, long size) {
/* step 1 */
assert size >= 0;
/* step 2 */
if (size > Integer.MAX_VALUE) {
throw newRangeError(cx, Messages.Key.OutOfMemory);
}
// Align requested size to int32-size to allow access with Unsafe#compareAndSwapInt().
int requestedSize = ((int) size + 0b11) & ~0b11;
// Overflow detection.
if (requestedSize < 0) {
throw newRangeError(cx, Messages.Key.OutOfMemory);
}
try {
/* steps 3-4 */
// TODO: Call allocateDirect() if size exceeds predefined limit?
return ByteBuffer.allocate(requestedSize).order(ByteOrder.nativeOrder());
} catch (OutOfMemoryError e) {
/* step 2 */
throw newRangeError(cx, Messages.Key.OutOfMemoryVM);
}
}
/**
* SharedDataBlockID( block )
*
* @param block
* the byte buffer
* @return the byte buffer id
*/
public static Object SharedDataBlockID(ByteBuffer block) {
return block;
}
/**
* AllocateSharedArrayBuffer( constructor, byteLength )
*
* @param cx
* the execution context
* @param constructor
* the constructor function
* @param byteLength
* the buffer byte length
* @return the new shared array buffer object
*/
public static SharedArrayBufferObject AllocateSharedArrayBuffer(ExecutionContext cx, Constructor constructor,
long byteLength) {
/* steps 1-2 */
ScriptObject proto = GetPrototypeFromConstructor(cx, constructor, Intrinsics.SharedArrayBufferPrototype);
/* step 3 */
assert byteLength >= 0;
/* steps 4-5 */
ByteBuffer block = CreateSharedByteDataBlock(cx, byteLength);
/* steps 1-2, 6-8 */
return new SharedArrayBufferObject(cx.getRealm(), block, byteLength, proto);
}
/**
* IsSharedMemory( obj )
*
* @param obj
* the object
* @return {@code true} if the buffer is shared array buffer object
*/
public static boolean IsSharedMemory(ArrayBuffer obj) {
return obj instanceof SharedArrayBufferObject;
}
/**
* SharedArrayBuffer(length)
*/
@Override
public SharedArrayBufferObject call(ExecutionContext callerContext, Object thisValue, Object... args) {
/* step 1 */
throw newTypeError(calleeContext(), Messages.Key.InvalidCall, "SharedArrayBuffer");
}
/**
* SharedArrayBuffer(length)
*/
@Override
public SharedArrayBufferObject construct(ExecutionContext callerContext, Constructor newTarget, Object... args) {
ExecutionContext calleeContext = calleeContext();
Object length = argument(args, 0);
/* step 1 (not applicable) */
/* step 2 */
double numberLength = ToNumber(calleeContext, length);
/* steps 3-4 */
long byteLength = ToLength(numberLength);
/* step 5 */
if (numberLength != byteLength) { // SameValueZero
throw newRangeError(calleeContext, Messages.Key.InvalidBufferSize);
}
/* step 6 */
return AllocateSharedArrayBuffer(calleeContext, newTarget, byteLength);
}
/**
* Properties of the SharedArrayBuffer Constructor
*/
public enum Properties {
;
@Prototype
public static final Intrinsics __proto__ = Intrinsics.FunctionPrototype;
@Value(name = "length", attributes = @Attributes(writable = false, enumerable = false, configurable = true) )
public static final int length = 1;
@Value(name = "name", attributes = @Attributes(writable = false, enumerable = false, configurable = true) )
public static final String name = "SharedArrayBuffer";
/**
* SharedArrayBuffer.prototype
*/
@Value(name = "prototype",
attributes = @Attributes(writable = false, enumerable = false, configurable = false) )
public static final Intrinsics prototype = Intrinsics.SharedArrayBufferPrototype;
/**
* SharedArrayBuffer.isView ( arg )
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @param arg
* the argument object
* @return {@code true} if the argument is an array buffer view object
*/
@Function(name = "isView", arity = 1)
public static Object isView(ExecutionContext cx, Object thisValue, Object arg) {
/* steps 1-3 */
return arg instanceof ArrayBufferView;
}
/**
* get SharedArrayBuffer [ @@species ]
*
* @param cx
* the execution context
* @param thisValue
* the function this-value
* @return the species object
*/
@Accessor(name = "get [Symbol.species]", symbol = BuiltinSymbol.species, type = Accessor.Type.Getter)
public static Object species(ExecutionContext cx, Object thisValue) {
/* step 1 */
return thisValue;
}
}
}