removing dependency on pxt-calliope-core
This commit is contained in:
		
							
								
								
									
										373
									
								
								libs/core/ManagedBuffer.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										373
									
								
								libs/core/ManagedBuffer.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,373 @@
 | 
				
			|||||||
 | 
					#include "MicroBit.h"
 | 
				
			||||||
 | 
					#include "ManagedBuffer.h"
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char empty[] __attribute__ ((aligned (4))) = "\xff\xff\0\0\0";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Internal constructor helper.
 | 
				
			||||||
 | 
					  * Configures this ManagedBuffer to refer to the static empty buffer.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					void ManagedBuffer::initEmpty()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ptr = (BufferData*)(void*)empty;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Default Constructor. 
 | 
				
			||||||
 | 
					 * Creates an empty ManagedBuffer. 
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Example:
 | 
				
			||||||
 | 
					 * @code
 | 
				
			||||||
 | 
					 * ManagedBuffer p(); 
 | 
				
			||||||
 | 
					 * @endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ManagedBuffer::ManagedBuffer()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    initEmpty();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Constructor. 
 | 
				
			||||||
 | 
					 * Creates an empty ManagedBuffer of the given size. 
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param length The length of the buffer to create.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Example:
 | 
				
			||||||
 | 
					 * @code
 | 
				
			||||||
 | 
					 * ManagedBuffer p(16);         // Creates a ManagedBuffer 16 bytes long.
 | 
				
			||||||
 | 
					 * @endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ManagedBuffer::ManagedBuffer(int length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    this->init(NULL, length);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Constructor. 
 | 
				
			||||||
 | 
					 * Creates a new ManagedBuffer of the given size,
 | 
				
			||||||
 | 
					 * and fills it with the data provided.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param data The data with which to fill the buffer.
 | 
				
			||||||
 | 
					 * @param length The length of the buffer to create.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Example:
 | 
				
			||||||
 | 
					 * @code
 | 
				
			||||||
 | 
					 * uint8_t buf = {13,5,2};
 | 
				
			||||||
 | 
					 * ManagedBuffer p(buf, 3);         // Creates a ManagedBuffer 3 bytes long.
 | 
				
			||||||
 | 
					 * @endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ManagedBuffer::ManagedBuffer(uint8_t *data, int length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    this->init(data, length);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copy Constructor. 
 | 
				
			||||||
 | 
					 * Add ourselves as a reference to an existing ManagedBuffer.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * @param buffer The ManagedBuffer to reference.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Example:
 | 
				
			||||||
 | 
					 * @code
 | 
				
			||||||
 | 
					 * ManagedBuffer p();
 | 
				
			||||||
 | 
					 * ManagedBuffer p2(i);        // Refers to the same buffer as p. 
 | 
				
			||||||
 | 
					 * @endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ManagedBuffer::ManagedBuffer(const ManagedBuffer &buffer)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ptr = buffer.ptr;
 | 
				
			||||||
 | 
					    ptr->incr();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Constructor. 
 | 
				
			||||||
 | 
					  * Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes.
 | 
				
			||||||
 | 
					  *
 | 
				
			||||||
 | 
					  * @param p The pointer to use.
 | 
				
			||||||
 | 
					  */    
 | 
				
			||||||
 | 
					ManagedBuffer::ManagedBuffer(BufferData *p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ptr = p;
 | 
				
			||||||
 | 
					    ptr->incr();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Internal constructor-initialiser.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param data The data with which to fill the buffer.
 | 
				
			||||||
 | 
					 * @param length The length of the buffer to create.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void ManagedBuffer::init(uint8_t *data, int length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (length <= 0) {
 | 
				
			||||||
 | 
					        initEmpty();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr = (BufferData *) malloc(sizeof(BufferData) + length);
 | 
				
			||||||
 | 
					    ptr->init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr->length = length;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Copy in the data buffer, if provided.
 | 
				
			||||||
 | 
					    if (data)
 | 
				
			||||||
 | 
					        memcpy(ptr->payload, data, length);
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        memset(ptr->payload, 0, length);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Destructor. 
 | 
				
			||||||
 | 
					 * Removes buffer resources held by the instance.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ManagedBuffer::~ManagedBuffer()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    ptr->decr();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Copy assign operation. 
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Called when one ManagedBuffer is assigned the value of another using the '=' operator.
 | 
				
			||||||
 | 
					 * Decrements our reference count and free up the buffer as necessary.
 | 
				
			||||||
 | 
					 * Then, update our buffer to refer to that of the supplied ManagedBuffer,
 | 
				
			||||||
 | 
					 * and increase its reference count.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param p The ManagedBuffer to reference.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Example:
 | 
				
			||||||
 | 
					 * @code
 | 
				
			||||||
 | 
					 * uint8_t buf = {13,5,2};
 | 
				
			||||||
 | 
					 * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					 * ManagedBuffer p2(buf, 3);        
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * p1 = p2;  
 | 
				
			||||||
 | 
					 * @endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					ManagedBuffer& ManagedBuffer::operator = (const ManagedBuffer &p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if(ptr == p.ptr)
 | 
				
			||||||
 | 
					        return *this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ptr->decr();
 | 
				
			||||||
 | 
					    ptr = p.ptr;
 | 
				
			||||||
 | 
					    ptr->incr();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return *this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Equality operation.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Called when one ManagedBuffer is tested to be equal to another using the '==' operator.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param p The ManagedBuffer to test ourselves against.
 | 
				
			||||||
 | 
					 * @return true if this ManagedBuffer is identical to the one supplied, false otherwise.
 | 
				
			||||||
 | 
					 * 
 | 
				
			||||||
 | 
					 * Example:
 | 
				
			||||||
 | 
					 * @code
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * uint8_t buf = {13,5,2};
 | 
				
			||||||
 | 
					 * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					 * ManagedBuffer p2(buf, 3);        
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * if(p1 == p2)                    // will be true
 | 
				
			||||||
 | 
					 *     uBit.display.scroll("same!");
 | 
				
			||||||
 | 
					 * @endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					bool ManagedBuffer::operator== (const ManagedBuffer& p)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (ptr == p.ptr)
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return (ptr->length == p.ptr->length && (memcmp(ptr->payload, p.ptr->payload, ptr->length)==0));    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Sets the byte at the given index to value provided.
 | 
				
			||||||
 | 
					 * @param position The index of the byte to change.
 | 
				
			||||||
 | 
					 * @param value The new value of the byte (0-255).
 | 
				
			||||||
 | 
					 * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Example:
 | 
				
			||||||
 | 
					 * @code
 | 
				
			||||||
 | 
					 * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					 * p1.setByte(0,255);              // Sets the firts byte in the buffer to the value 255.
 | 
				
			||||||
 | 
					 * @endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int ManagedBuffer::setByte(int position, uint8_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (0 <= position && position < ptr->length)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ptr->payload[position] = value;
 | 
				
			||||||
 | 
					        return MICROBIT_OK;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return MICROBIT_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Determines the value of the given byte in the buffer.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param position The index of the byte to read.
 | 
				
			||||||
 | 
					 * @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Example:
 | 
				
			||||||
 | 
					 * @code
 | 
				
			||||||
 | 
					 * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					 * p1.setByte(0,255);              // Sets the firts byte in the buffer to the value 255.
 | 
				
			||||||
 | 
					 * p1.getByte(0);                  // Returns 255.
 | 
				
			||||||
 | 
					 * @endcode
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int ManagedBuffer::getByte(int position)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (0 <= position && position < ptr->length)
 | 
				
			||||||
 | 
					        return ptr->payload[position];
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        return MICROBIT_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					} 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Get current ptr, do not decr() it, and set the current instance to an empty buffer.
 | 
				
			||||||
 | 
					  * This is to be used by specialized runtimes which pass BufferData around.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					BufferData *ManagedBuffer::leakData()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BufferData* res = ptr;
 | 
				
			||||||
 | 
					    initEmpty();
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ManagedBuffer::fill(uint8_t value, int offset, int length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (offset < 0 || offset > ptr->length)
 | 
				
			||||||
 | 
					        return MICROBIT_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					    if (length < 0)
 | 
				
			||||||
 | 
					        length = ptr->length;
 | 
				
			||||||
 | 
					    length = min(length, ptr->length - offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    memset(ptr->payload + offset, value, length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return MICROBIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ManagedBuffer ManagedBuffer::slice(int offset, int length) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    offset = min(ptr->length, offset);
 | 
				
			||||||
 | 
					    if (length < 0)
 | 
				
			||||||
 | 
					        length = ptr->length;
 | 
				
			||||||
 | 
					    length = min(length, ptr->length - offset);
 | 
				
			||||||
 | 
					    return ManagedBuffer(ptr->payload + offset, length);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ManagedBuffer::shift(int offset, int start, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (len < 0) len = ptr->length - start;    
 | 
				
			||||||
 | 
					    if (start < 0 || start + len > ptr->length || start + len < start
 | 
				
			||||||
 | 
					        || len == 0 || offset == 0 || offset == INT_MIN) return;
 | 
				
			||||||
 | 
					    if (offset <= -len || offset >= len) {
 | 
				
			||||||
 | 
					        fill(0);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    uint8_t *data = ptr->payload + start;
 | 
				
			||||||
 | 
					    if (offset < 0) {
 | 
				
			||||||
 | 
					        offset = -offset;
 | 
				
			||||||
 | 
					        memmove(data + offset, data, len - offset);
 | 
				
			||||||
 | 
					        memset(data, 0, offset);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        len = len - offset;
 | 
				
			||||||
 | 
					        memmove(data, data + offset, len);
 | 
				
			||||||
 | 
					        memset(data + len, 0, offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ManagedBuffer::rotate(int offset, int start, int len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (len < 0) len = ptr->length - start;
 | 
				
			||||||
 | 
					    if (start < 0 || start + len > ptr-> length || start + len < start
 | 
				
			||||||
 | 
					        || len == 0 || offset == 0 || offset == INT_MIN) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (offset < 0)
 | 
				
			||||||
 | 
					        offset += len << 8; // try to make it positive
 | 
				
			||||||
 | 
					    offset %= len;
 | 
				
			||||||
 | 
					    if (offset < 0)
 | 
				
			||||||
 | 
					        offset += len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t *data = ptr->payload + start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint8_t *n_first = data + offset;
 | 
				
			||||||
 | 
					    uint8_t *first = data;
 | 
				
			||||||
 | 
					    uint8_t *next = n_first;
 | 
				
			||||||
 | 
					    uint8_t *last = data + len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    while (first != next) {
 | 
				
			||||||
 | 
					        uint8_t tmp = *first;
 | 
				
			||||||
 | 
					        *first++ = *next;
 | 
				
			||||||
 | 
					        *next++ = tmp;
 | 
				
			||||||
 | 
					        if (next == last) {
 | 
				
			||||||
 | 
					            next = n_first;
 | 
				
			||||||
 | 
					        } else if (first == n_first) {
 | 
				
			||||||
 | 
					            n_first = next;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ManagedBuffer::writeBuffer(int dstOffset, const ManagedBuffer &src, int srcOffset, int length)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (length < 0)
 | 
				
			||||||
 | 
					        length = src.length();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (srcOffset < 0 || dstOffset < 0 || dstOffset > ptr->length)
 | 
				
			||||||
 | 
					        return MICROBIT_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    length = min(src.length() - srcOffset, ptr->length - dstOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (length < 0)
 | 
				
			||||||
 | 
					        return MICROBIT_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (ptr == src.ptr) {
 | 
				
			||||||
 | 
					        memmove(getBytes() + dstOffset, src.ptr->payload + srcOffset, length);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        memcpy(getBytes() + dstOffset, src.ptr->payload + srcOffset, length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return MICROBIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ManagedBuffer::writeBytes(int offset, uint8_t *src, int length, bool swapBytes)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (offset < 0 || length < 0 || offset + length > ptr->length)
 | 
				
			||||||
 | 
					        return MICROBIT_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (swapBytes) {
 | 
				
			||||||
 | 
					        uint8_t *p = ptr->payload + offset + length;
 | 
				
			||||||
 | 
					        for (int i = 0; i < length; ++i)
 | 
				
			||||||
 | 
					            *--p = src[i];
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        memcpy(ptr->payload + offset, src, length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return MICROBIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int ManagedBuffer::readBytes(uint8_t *dst, int offset, int length, bool swapBytes) const
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (offset < 0 || length < 0 || offset + length > ptr->length)
 | 
				
			||||||
 | 
					        return MICROBIT_INVALID_PARAMETER;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (swapBytes) {
 | 
				
			||||||
 | 
					        uint8_t *p = ptr->payload + offset + length;
 | 
				
			||||||
 | 
					        for (int i = 0; i < length; ++i)
 | 
				
			||||||
 | 
					            dst[i] = *--p;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        memcpy(dst, ptr->payload + offset, length);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return MICROBIT_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										257
									
								
								libs/core/ManagedBuffer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										257
									
								
								libs/core/ManagedBuffer.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,257 @@
 | 
				
			|||||||
 | 
					#ifndef MICROBIT_MANAGED_BUFFER_H
 | 
				
			||||||
 | 
					#define MICROBIT_MANAGED_BUFFER_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "mbed.h"
 | 
				
			||||||
 | 
					#include "RefCounted.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct BufferData : RefCounted
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    uint16_t        length;             // The length of the payload in bytes
 | 
				
			||||||
 | 
					    uint8_t         payload[0];         // ManagedBuffer data
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					  * Class definition for a ManagedBuffer.
 | 
				
			||||||
 | 
					  * A ManagedBuffer holds a series of bytes, used with MicroBitRadio channels and in other places.
 | 
				
			||||||
 | 
					  * n.b. This is a mutable, managed type.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					class ManagedBuffer
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    BufferData      *ptr;     // Pointer to payload data
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Default Constructor. 
 | 
				
			||||||
 | 
					      * Creates an empty ManagedBuffer.  The 'ptr' field in all empty buffers is shared.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      * ManagedBuffer p(); 
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    ManagedBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Constructor. 
 | 
				
			||||||
 | 
					      * Creates a new ManagedBuffer of the given size. 
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * @param length The length of the buffer to create.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      * ManagedBuffer p(16);         // Creates a ManagedBuffer 16 bytes long.
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    ManagedBuffer(int length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Constructor. 
 | 
				
			||||||
 | 
					      * Creates an empty ManagedBuffer of the given size,
 | 
				
			||||||
 | 
					      * and fills it with the data provided.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * @param data The data with which to fill the buffer.
 | 
				
			||||||
 | 
					      * @param length The length of the buffer to create.
 | 
				
			||||||
 | 
					      * 
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      * uint8_t buf[] = {13,5,2};
 | 
				
			||||||
 | 
					      * ManagedBuffer p(buf, 3);         // Creates a ManagedBuffer 3 bytes long.
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    ManagedBuffer(uint8_t *data, int length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Copy Constructor. 
 | 
				
			||||||
 | 
					      * Add ourselves as a reference to an existing ManagedBuffer.
 | 
				
			||||||
 | 
					      * 
 | 
				
			||||||
 | 
					      * @param buffer The ManagedBuffer to reference.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      * ManagedBuffer p();
 | 
				
			||||||
 | 
					      * ManagedBuffer p2(i);        // Refers to the same buffer as p. 
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    ManagedBuffer(const ManagedBuffer &buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Constructor. 
 | 
				
			||||||
 | 
					      * Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * @param p The pointer to use.
 | 
				
			||||||
 | 
					      */    
 | 
				
			||||||
 | 
					    ManagedBuffer(BufferData *p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Internal constructor helper.
 | 
				
			||||||
 | 
					      * Configures this ManagedBuffer to refer to the static empty buffer.
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    void initEmpty();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Internal constructor-initialiser.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param data The data with which to fill the buffer.
 | 
				
			||||||
 | 
					     * @param length The length of the buffer to create.
 | 
				
			||||||
 | 
					     * 
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    void init(uint8_t *data, int length);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Destructor. 
 | 
				
			||||||
 | 
					      * Removes buffer resources held by the instance.
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    ~ManagedBuffer();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Provide an array containing the buffer data.
 | 
				
			||||||
 | 
					      * @return The contents of this buffer, as an array of bytes.
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    uint8_t *getBytes()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ptr->payload;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Get current ptr, do not decr() it, and set the current instance to an empty buffer.
 | 
				
			||||||
 | 
					      * This is to be used by specialized runtimes which pass BufferData around.
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    BufferData *leakData();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Copy assign operation. 
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * Called when one ManagedBuffer is assigned the value of another using the '=' operator.
 | 
				
			||||||
 | 
					      * Decrements our reference count and free up the buffer as necessary.
 | 
				
			||||||
 | 
					      * Then, update our buffer to refer to that of the supplied ManagedBuffer,
 | 
				
			||||||
 | 
					      * and increase its reference count.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * @param p The ManagedBuffer to reference.
 | 
				
			||||||
 | 
					      * 
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      * uint8_t buf = {13,5,2};
 | 
				
			||||||
 | 
					      * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					      * ManagedBuffer p2(buf, 3);        
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * p1 = p2;  
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    ManagedBuffer& operator = (const ManagedBuffer& p);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Array access operation (read). 
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Called when a ManagedBuffer is dereferenced with a [] operation.
 | 
				
			||||||
 | 
					     * Transparently map this through to the underlying payload for elegance of programming.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Example:
 | 
				
			||||||
 | 
					     * @code
 | 
				
			||||||
 | 
					     * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					     * uint8_t data = p1[0];
 | 
				
			||||||
 | 
					     * @endcode
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    uint8_t operator [] (int i) const
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ptr->payload[i];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Array access operation (modify). 
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Called when a ManagedBuffer is dereferenced with a [] operation.
 | 
				
			||||||
 | 
					     * Transparently map this through to the underlying payload for elegance of programming.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * Example:
 | 
				
			||||||
 | 
					     * @code
 | 
				
			||||||
 | 
					     * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					     * p1[0] = 42;
 | 
				
			||||||
 | 
					     * @endcode
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    uint8_t& operator [] (int i)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return ptr->payload[i];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Equality operation.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * Called when one ManagedBuffer is tested to be equal to another using the '==' operator.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * @param p The ManagedBuffer to test ourselves against.
 | 
				
			||||||
 | 
					      * @return true if this ManagedBuffer is identical to the one supplied, false otherwise.
 | 
				
			||||||
 | 
					      * 
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * uint8_t buf = {13,5,2};
 | 
				
			||||||
 | 
					      * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					      * ManagedBuffer p2(buf, 3);        
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * if(p1 == p2)                    // will be true
 | 
				
			||||||
 | 
					      *     uBit.display.scroll("same!");
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    bool operator== (const ManagedBuffer& p);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Sets the byte at the given index to value provided.
 | 
				
			||||||
 | 
					      * @param position The index of the byte to change.
 | 
				
			||||||
 | 
					      * @param value The new value of the byte (0-255).
 | 
				
			||||||
 | 
					      * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					      * p1.setByte(0,255);              // Sets the first byte in the buffer to the value 255.
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    int setByte(int position, uint8_t value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Determines the value of the given byte in the buffer.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * @param position The index of the byte to read.
 | 
				
			||||||
 | 
					      * @return The value of the byte at the given position, or MICROBIT_INVALID_PARAMETER.
 | 
				
			||||||
 | 
					      *
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					      * p1.setByte(0,255);              // Sets the first byte in the buffer to the value 255.
 | 
				
			||||||
 | 
					      * p1.getByte(0);                  // Returns 255.
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    int getByte(int position);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					      * Gets number of bytes in this buffer 
 | 
				
			||||||
 | 
					      * @return The size of the buffer in bytes.
 | 
				
			||||||
 | 
					      * 
 | 
				
			||||||
 | 
					      * Example:
 | 
				
			||||||
 | 
					      * @code
 | 
				
			||||||
 | 
					      * ManagedBuffer p1(16); 
 | 
				
			||||||
 | 
					      * p1.length();                 // Returns 16.
 | 
				
			||||||
 | 
					      * @endcode
 | 
				
			||||||
 | 
					      */
 | 
				
			||||||
 | 
					    int length() const { return ptr->length; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int fill(uint8_t value, int offset = 0, int length = -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ManagedBuffer slice(int offset = 0, int length = -1) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void shift(int offset, int start = 0, int length = -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void rotate(int offset, int start = 0, int length = -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int readBytes(uint8_t *dst, int offset, int length, bool swapBytes = false) const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int writeBytes(int dstOffset, uint8_t *src, int length, bool swapBytes = false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int writeBuffer(int dstOffset, const ManagedBuffer &src, int srcOffset = 0, int length = -1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool isReadOnly() const { return ptr->isReadOnly(); }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										472
									
								
								libs/core/pxt.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										472
									
								
								libs/core/pxt.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,472 @@
 | 
				
			|||||||
 | 
					#include "pxt.h"
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					MicroBit uBit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxt {
 | 
				
			||||||
 | 
					    int incr(uint32_t e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      if (e) {
 | 
				
			||||||
 | 
					        if (hasVTable(e))
 | 
				
			||||||
 | 
					          ((RefObject*)e)->ref();
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          ((RefCounted*)e)->incr();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return e;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void decr(uint32_t e)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      if (e) {
 | 
				
			||||||
 | 
					        if (hasVTable(e))
 | 
				
			||||||
 | 
					          ((RefObject*)e)->unref();
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					          ((RefCounted*)e)->decr();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Action mkAction(int reflen, int totallen, int startptr)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      check(0 <= reflen && reflen <= totallen, ERR_SIZE, 1);
 | 
				
			||||||
 | 
					      check(reflen <= totallen && totallen <= 255, ERR_SIZE, 2);
 | 
				
			||||||
 | 
					      check(bytecode[startptr] == 0xffff, ERR_INVALID_BINARY_HEADER, 3);
 | 
				
			||||||
 | 
					      check(bytecode[startptr + 1] == 0, ERR_INVALID_BINARY_HEADER, 4);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      uint32_t tmp = (uint32_t)&bytecode[startptr];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (totallen == 0) {
 | 
				
			||||||
 | 
					        return tmp; // no closure needed
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      void *ptr = ::operator new(sizeof(RefAction) + totallen * sizeof(uint32_t));
 | 
				
			||||||
 | 
					      RefAction *r = new (ptr) RefAction();
 | 
				
			||||||
 | 
					      r->len = totallen;
 | 
				
			||||||
 | 
					      r->reflen = reflen;
 | 
				
			||||||
 | 
					      r->func = (ActionCB)((tmp + 4) | 1);
 | 
				
			||||||
 | 
					      memset(r->fields, 0, r->len * sizeof(uint32_t));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return (Action)r;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t runAction3(Action a, int arg0, int arg1, int arg2)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      if (hasVTable(a))
 | 
				
			||||||
 | 
					        return ((RefAction*)a)->runCore(arg0, arg1, arg2);
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        check(*(uint16_t*)a == 0xffff, ERR_INVALID_BINARY_HEADER, 4);
 | 
				
			||||||
 | 
					        return ((ActionCB)((a + 4) | 1))(NULL, arg0, arg1, arg2);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t runAction2(Action a, int arg0, int arg1)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      return runAction3(a, arg0, arg1, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t runAction1(Action a, int arg0)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      return runAction3(a, arg0, 0, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t runAction0(Action a)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      return runAction3(a, 0, 0, 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RefRecord* mkClassInstance(int vtableOffset)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      VTable *vtable = (VTable*)&bytecode[vtableOffset];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      intcheck(vtable->methods[0] == &RefRecord_destroy, ERR_SIZE, 3);
 | 
				
			||||||
 | 
					      intcheck(vtable->methods[1] == &RefRecord_print, ERR_SIZE, 4);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					      void *ptr = ::operator new(vtable->numbytes);
 | 
				
			||||||
 | 
					      RefRecord *r = new (ptr) RefRecord(PXT_VTABLE_TO_INT(vtable));
 | 
				
			||||||
 | 
					      memset(r->fields, 0, vtable->numbytes - sizeof(RefRecord));
 | 
				
			||||||
 | 
					      return r;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t RefRecord::ld(int idx)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      //intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, ERR_OUT_OF_BOUNDS, 1);
 | 
				
			||||||
 | 
					      return fields[idx];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t RefRecord::ldref(int idx)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      //printf("LD %p len=%d reflen=%d idx=%d\n", this, len, reflen, idx);
 | 
				
			||||||
 | 
					      //intcheck(0 <= idx && idx < reflen, ERR_OUT_OF_BOUNDS, 2);
 | 
				
			||||||
 | 
					      uint32_t tmp = fields[idx];
 | 
				
			||||||
 | 
					      incr(tmp);
 | 
				
			||||||
 | 
					      return tmp;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefRecord::st(int idx, uint32_t v)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      //intcheck((reflen == 255 ? 0 : reflen) <= idx && idx < len, ERR_OUT_OF_BOUNDS, 3);
 | 
				
			||||||
 | 
					      fields[idx] = v;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefRecord::stref(int idx, uint32_t v)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      //printf("ST %p len=%d reflen=%d idx=%d\n", this, len, reflen, idx);
 | 
				
			||||||
 | 
					      //intcheck(0 <= idx && idx < reflen, ERR_OUT_OF_BOUNDS, 4);
 | 
				
			||||||
 | 
					      decr(fields[idx]);
 | 
				
			||||||
 | 
					      fields[idx] = v;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefObject::destroy() {
 | 
				
			||||||
 | 
					      ((RefObjectMethod)getVTable()->methods[0])(this);
 | 
				
			||||||
 | 
					      delete this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefObject::print() {
 | 
				
			||||||
 | 
					      ((RefObjectMethod)getVTable()->methods[1])(this);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefRecord_destroy(RefRecord *r) {
 | 
				
			||||||
 | 
					        auto tbl = r->getVTable();
 | 
				
			||||||
 | 
					        uint8_t *refmask = (uint8_t*)&tbl->methods[tbl->userdata & 0xff];
 | 
				
			||||||
 | 
					        int len = (tbl->numbytes >> 2) - 1;
 | 
				
			||||||
 | 
					        for (int i = 0; i < len; ++i) {
 | 
				
			||||||
 | 
					          if (refmask[i]) decr(r->fields[i]);
 | 
				
			||||||
 | 
					          r->fields[i] = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefRecord_print(RefRecord *r)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      printf("RefRecord %p r=%d size=%d bytes\n", r, r->refcnt, r->getVTable()->numbytes);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefCollection::push(uint32_t x) {
 | 
				
			||||||
 | 
					      if (isRef()) incr(x);
 | 
				
			||||||
 | 
					      data.push_back(x);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t RefCollection::getAt(int x) {
 | 
				
			||||||
 | 
					      if (in_range(x)) {
 | 
				
			||||||
 | 
					        uint32_t tmp = data.at(x);
 | 
				
			||||||
 | 
					        if (isRef()) incr(tmp);
 | 
				
			||||||
 | 
					        return tmp;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      else {
 | 
				
			||||||
 | 
					        error(ERR_OUT_OF_BOUNDS);
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefCollection::removeAt(int x) {
 | 
				
			||||||
 | 
					      if (!in_range(x))
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (isRef()) decr(data.at(x));
 | 
				
			||||||
 | 
					      data.erase(data.begin()+x);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefCollection::setAt(int x, uint32_t y) {
 | 
				
			||||||
 | 
					      if (!in_range(x))
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (isRef()) {
 | 
				
			||||||
 | 
					        decr(data.at(x));
 | 
				
			||||||
 | 
					        incr(y);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      data.at(x) = y;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int RefCollection::indexOf(uint32_t x, int start) {
 | 
				
			||||||
 | 
					      if (!in_range(start))
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (isString()) {
 | 
				
			||||||
 | 
					        StringData *xx = (StringData*)x;
 | 
				
			||||||
 | 
					        for (uint32_t i = start; i < data.size(); ++i) {
 | 
				
			||||||
 | 
					          StringData *ee = (StringData*)data.at(i);
 | 
				
			||||||
 | 
					          if (xx->len == ee->len && memcmp(xx->data, ee->data, xx->len) == 0)
 | 
				
			||||||
 | 
					            return (int)i;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        for (uint32_t i = start; i < data.size(); ++i)
 | 
				
			||||||
 | 
					          if (data.at(i) == x)
 | 
				
			||||||
 | 
					            return (int)i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int RefCollection::removeElement(uint32_t x) {
 | 
				
			||||||
 | 
					      int idx = indexOf(x, 0);
 | 
				
			||||||
 | 
					      if (idx >= 0) {
 | 
				
			||||||
 | 
					        removeAt(idx);
 | 
				
			||||||
 | 
					        return 1;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    namespace Coll0 {
 | 
				
			||||||
 | 
					      PXT_VTABLE_BEGIN(RefCollection, 0, 0)
 | 
				
			||||||
 | 
					      PXT_VTABLE_END
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    namespace Coll1 {
 | 
				
			||||||
 | 
					      PXT_VTABLE_BEGIN(RefCollection, 1, 0)
 | 
				
			||||||
 | 
					      PXT_VTABLE_END
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    namespace Coll3 {
 | 
				
			||||||
 | 
					      PXT_VTABLE_BEGIN(RefCollection, 3, 0)
 | 
				
			||||||
 | 
					      PXT_VTABLE_END
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RefCollection::RefCollection(uint16_t flags) : RefObject(0) {
 | 
				
			||||||
 | 
					      switch (flags) {
 | 
				
			||||||
 | 
					        case 0:
 | 
				
			||||||
 | 
					          vtable = PXT_VTABLE_TO_INT(&Coll0::RefCollection_vtable);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case 1:
 | 
				
			||||||
 | 
					          vtable = PXT_VTABLE_TO_INT(&Coll1::RefCollection_vtable);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        case 3:
 | 
				
			||||||
 | 
					          vtable = PXT_VTABLE_TO_INT(&Coll3::RefCollection_vtable);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					          error(ERR_SIZE);
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefCollection::destroy()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      if (this->isRef())
 | 
				
			||||||
 | 
					        for (uint32_t i = 0; i < this->data.size(); ++i) {
 | 
				
			||||||
 | 
					          decr(this->data[i]);
 | 
				
			||||||
 | 
					          this->data[i] = 0;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      this->data.resize(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefCollection::print()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      printf("RefCollection %p r=%d flags=%d size=%d [%p, ...]\n", this, refcnt, getFlags(), data.size(), data.size() > 0 ? data[0] : 0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PXT_VTABLE_CTOR(RefAction) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // fields[] contain captured locals
 | 
				
			||||||
 | 
					    void RefAction::destroy()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      for (int i = 0; i < this->reflen; ++i) {
 | 
				
			||||||
 | 
					        decr(fields[i]);
 | 
				
			||||||
 | 
					        fields[i] = 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefAction::print()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      printf("RefAction %p r=%d pc=0x%lx size=%d (%d refs)\n", this, refcnt, (const uint8_t*)func - (const uint8_t*)bytecode, len, reflen);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefLocal::print()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      printf("RefLocal %p r=%d v=%d\n", this, refcnt, v);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefLocal::destroy()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PXT_VTABLE_CTOR(RefLocal) {
 | 
				
			||||||
 | 
					      v = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PXT_VTABLE_CTOR(RefRefLocal) {
 | 
				
			||||||
 | 
					      v = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefRefLocal::print()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      printf("RefRefLocal %p r=%d v=%p\n", this, refcnt, (void*)v);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefRefLocal::destroy()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      decr(v);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    PXT_VTABLE_BEGIN(RefMap, 0, RefMapMarker)
 | 
				
			||||||
 | 
					    PXT_VTABLE_END
 | 
				
			||||||
 | 
					    RefMap::RefMap() : PXT_VTABLE_INIT(RefMap) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefMap::destroy() {
 | 
				
			||||||
 | 
					      for (unsigned i = 0; i < data.size(); ++i) {
 | 
				
			||||||
 | 
					        if (data[i].key & 1) {
 | 
				
			||||||
 | 
					          decr(data[i].val);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        data[i].val = 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      data.resize(0);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int RefMap::findIdx(uint32_t key) {
 | 
				
			||||||
 | 
					      for (unsigned i = 0; i < data.size(); ++i) {
 | 
				
			||||||
 | 
					        if (data[i].key >> 1 == key)
 | 
				
			||||||
 | 
					          return i;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void RefMap::print()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      printf("RefMap %p r=%d size=%d\n", this, refcnt, data.size());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_MEMLEAKS
 | 
				
			||||||
 | 
					  std::set<RefObject*> allptrs;
 | 
				
			||||||
 | 
					  void debugMemLeaks()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    printf("LIVE POINTERS:\n");
 | 
				
			||||||
 | 
					    for(std::set<RefObject*>::iterator itr = allptrs.begin();itr!=allptrs.end();itr++)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      (*itr)->print();
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					    printf("\n");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					  void debugMemLeaks() {}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // ---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					    // An adapter for the API expected by the run-time.
 | 
				
			||||||
 | 
					    // ---------------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    map<pair<int, int>, Action> handlersMap;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    MicroBitEvent lastEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // We have the invariant that if [dispatchEvent] is registered against the DAL
 | 
				
			||||||
 | 
					    // for a given event, then [handlersMap] contains a valid entry for that
 | 
				
			||||||
 | 
					    // event.
 | 
				
			||||||
 | 
					    void dispatchEvent(MicroBitEvent e) {
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      lastEvent = e;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      Action curr = handlersMap[{ e.source, e.value }];
 | 
				
			||||||
 | 
					      if (curr)
 | 
				
			||||||
 | 
					        runAction1(curr, e.value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      curr = handlersMap[{ e.source, MICROBIT_EVT_ANY }];
 | 
				
			||||||
 | 
					      if (curr)
 | 
				
			||||||
 | 
					        runAction1(curr, e.value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void registerWithDal(int id, int event, Action a) {
 | 
				
			||||||
 | 
					      Action prev = handlersMap[{ id, event }];
 | 
				
			||||||
 | 
					      if (prev)
 | 
				
			||||||
 | 
					        decr(prev);
 | 
				
			||||||
 | 
					      else
 | 
				
			||||||
 | 
					        uBit.messageBus.listen(id, event, dispatchEvent);
 | 
				
			||||||
 | 
					      incr(a);
 | 
				
			||||||
 | 
					      handlersMap[{ id, event }] = a;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void fiberDone(void *a)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      decr((Action)a);
 | 
				
			||||||
 | 
					      release_fiber();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void runInBackground(Action a) {
 | 
				
			||||||
 | 
					      if (a != 0) {
 | 
				
			||||||
 | 
					        incr(a);
 | 
				
			||||||
 | 
					        create_fiber((void(*)(void*))runAction0, (void*)a, fiberDone);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void error(ERROR code, int subcode)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    printf("Error: %d [%d]\n", code, subcode);
 | 
				
			||||||
 | 
					    uBit.panic(42);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint16_t *bytecode;
 | 
				
			||||||
 | 
					  uint32_t *globals;
 | 
				
			||||||
 | 
					  int numGlobals;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  uint32_t *allocate(uint16_t sz)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    uint32_t *arr = new uint32_t[sz];
 | 
				
			||||||
 | 
					    memset(arr, 0, sz * 4);
 | 
				
			||||||
 | 
					    return arr;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void checkStr(bool cond, const char *msg)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (!cond) {
 | 
				
			||||||
 | 
					      while (true) {
 | 
				
			||||||
 | 
					        uBit.display.scroll(msg, 100);
 | 
				
			||||||
 | 
					        uBit.sleep(100);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int templateHash()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return ((int*)bytecode)[4];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int programHash()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return ((int*)bytecode)[6];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int getNumGlobals()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return bytecode[16];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void exec_binary(int32_t *pc)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    // XXX re-enable once the calibration code is fixed and [editor/embedded.ts]
 | 
				
			||||||
 | 
					    // properly prepends a call to [internal_main].
 | 
				
			||||||
 | 
					    // ::touch_develop::internal_main();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // unique group for radio based on source hash
 | 
				
			||||||
 | 
					    // ::touch_develop::micro_bit::radioDefaultGroup = programHash();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // repeat error 4 times and restart as needed
 | 
				
			||||||
 | 
					    microbit_panic_timeout(4);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    int32_t ver = *pc++;
 | 
				
			||||||
 | 
					    checkStr(ver == 0x4209, ":( Bad runtime version");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bytecode = *((uint16_t**)pc++);  // the actual bytecode is here
 | 
				
			||||||
 | 
					    globals = allocate(getNumGlobals());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // just compare the first word
 | 
				
			||||||
 | 
					    checkStr(((uint32_t*)bytecode)[0] == 0x923B8E70 &&
 | 
				
			||||||
 | 
					             templateHash() == *pc,
 | 
				
			||||||
 | 
					             ":( Failed partial flash");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t startptr = (uint32_t)bytecode;
 | 
				
			||||||
 | 
					    startptr += 48; // header
 | 
				
			||||||
 | 
					    startptr |= 1; // Thumb state
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ((uint32_t (*)())startptr)();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_MEMLEAKS
 | 
				
			||||||
 | 
					    pxt::debugMemLeaks();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void start()
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    exec_binary((int32_t*)functionsAndBytecode);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// vim: ts=2 sw=2 expandtab
 | 
				
			||||||
							
								
								
									
										334
									
								
								libs/core/pxt.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										334
									
								
								libs/core/pxt.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,334 @@
 | 
				
			|||||||
 | 
					#ifndef __PXT_H
 | 
				
			||||||
 | 
					#define __PXT_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// #define DEBUG_MEMLEAKS 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma GCC diagnostic ignored "-Wunused-parameter"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "MicroBit.h"
 | 
				
			||||||
 | 
					#include "MicroBitImage.h"
 | 
				
			||||||
 | 
					#include "ManagedString.h"
 | 
				
			||||||
 | 
					#include "ManagedType.h"
 | 
				
			||||||
 | 
					#include "ManagedBuffer.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define printf(...) uBit.serial.printf(__VA_ARGS__)
 | 
				
			||||||
 | 
					// #define printf(...)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define intcheck(...) check(__VA_ARGS__)
 | 
				
			||||||
 | 
					//#define intcheck(...) do {} while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <vector>
 | 
				
			||||||
 | 
					#include <stdint.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef DEBUG_MEMLEAKS
 | 
				
			||||||
 | 
					#include <set>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern MicroBit uBit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace pxt {
 | 
				
			||||||
 | 
					  typedef uint32_t Action;
 | 
				
			||||||
 | 
					  typedef uint32_t ImageLiteral;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  typedef enum {
 | 
				
			||||||
 | 
					    ERR_INVALID_BINARY_HEADER = 5,
 | 
				
			||||||
 | 
					    ERR_OUT_OF_BOUNDS = 8,
 | 
				
			||||||
 | 
					    ERR_REF_DELETED = 7,
 | 
				
			||||||
 | 
					    ERR_SIZE = 9,
 | 
				
			||||||
 | 
					  } ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  extern const uint32_t functionsAndBytecode[];
 | 
				
			||||||
 | 
					  extern uint32_t *globals;
 | 
				
			||||||
 | 
					  extern uint16_t *bytecode;
 | 
				
			||||||
 | 
					  class RefRecord;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Utility functions
 | 
				
			||||||
 | 
					  extern MicroBitEvent lastEvent;
 | 
				
			||||||
 | 
					  void registerWithDal(int id, int event, Action a);
 | 
				
			||||||
 | 
					  void runInBackground(Action a);
 | 
				
			||||||
 | 
					  uint32_t runAction3(Action a, int arg0, int arg1, int arg2);
 | 
				
			||||||
 | 
					  uint32_t runAction2(Action a, int arg0, int arg1);
 | 
				
			||||||
 | 
					  uint32_t runAction1(Action a, int arg0);
 | 
				
			||||||
 | 
					  uint32_t runAction0(Action a);
 | 
				
			||||||
 | 
					  Action mkAction(int reflen, int totallen, int startptr);
 | 
				
			||||||
 | 
					  void error(ERROR code, int subcode = 0);
 | 
				
			||||||
 | 
					  void exec_binary(uint16_t *pc);
 | 
				
			||||||
 | 
					  void start();
 | 
				
			||||||
 | 
					  void debugMemLeaks();
 | 
				
			||||||
 | 
					  // allocate [sz] words and clear them
 | 
				
			||||||
 | 
					  uint32_t *allocate(uint16_t sz);
 | 
				
			||||||
 | 
					  int templateHash();
 | 
				
			||||||
 | 
					  int programHash();
 | 
				
			||||||
 | 
					  int getNumGlobals();
 | 
				
			||||||
 | 
					  RefRecord* mkClassInstance(int vtableOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // The standard calling convention is:
 | 
				
			||||||
 | 
					  //   - when a pointer is loaded from a local/global/field etc, and incr()ed
 | 
				
			||||||
 | 
					  //     (in other words, its presence on stack counts as a reference)
 | 
				
			||||||
 | 
					  //   - after a function call, all pointers are popped off the stack and decr()ed
 | 
				
			||||||
 | 
					  // This does not apply to the RefRecord and st/ld(ref) methods - they unref()
 | 
				
			||||||
 | 
					  // the RefRecord* this.
 | 
				
			||||||
 | 
					  int incr(uint32_t e);
 | 
				
			||||||
 | 
					  void decr(uint32_t e);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  inline void *ptrOfLiteral(int offset)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return &bytecode[offset];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  inline ImageData* imageBytes(int offset)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return (ImageData*)(void*)&bytecode[offset];
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Checks if object has a VTable, or if its RefCounted* from the runtime.
 | 
				
			||||||
 | 
					  inline bool hasVTable(uint32_t e)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    return (*((uint32_t*)e) & 1) == 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  inline void check(int cond, ERROR code, int subcode = 0)
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    if (!cond) error(code, subcode);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class RefObject;
 | 
				
			||||||
 | 
					#ifdef DEBUG_MEMLEAKS
 | 
				
			||||||
 | 
					  extern std::set<RefObject*> allptrs;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  typedef void (*RefObjectMethod)(RefObject *self);
 | 
				
			||||||
 | 
					  typedef void *PVoid;
 | 
				
			||||||
 | 
					  typedef void **PPVoid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const PPVoid RefMapMarker = (PPVoid)(void*)43;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct VTable {
 | 
				
			||||||
 | 
					    uint16_t numbytes;  // in the entire object, including the vtable pointer
 | 
				
			||||||
 | 
					    uint16_t userdata;
 | 
				
			||||||
 | 
					    PVoid *ifaceTable;
 | 
				
			||||||
 | 
					    PVoid methods[2]; // we only use up to two methods here; pxt will generate more
 | 
				
			||||||
 | 
					    // refmask sits at &methods[nummethods]
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const int vtableShift = 2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // A base abstract class for ref-counted objects.
 | 
				
			||||||
 | 
					  class RefObject
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    uint16_t refcnt;
 | 
				
			||||||
 | 
					    uint16_t vtable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RefObject(uint16_t vt)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      refcnt = 2;
 | 
				
			||||||
 | 
					      vtable = vt;
 | 
				
			||||||
 | 
					#ifdef DEBUG_MEMLEAKS
 | 
				
			||||||
 | 
					      allptrs.insert(this);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline VTable *getVTable() {
 | 
				
			||||||
 | 
					      return (VTable*)(vtable << vtableShift);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void destroy();
 | 
				
			||||||
 | 
					    void print();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Call to disable pointer tracking on the current instance (in destructor or some other hack)
 | 
				
			||||||
 | 
					    inline void untrack() {
 | 
				
			||||||
 | 
					#ifdef DEBUG_MEMLEAKS
 | 
				
			||||||
 | 
					      allptrs.erase(this);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Increment/decrement the ref-count. Decrementing to zero deletes the current object.
 | 
				
			||||||
 | 
					    inline void ref()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      check(refcnt > 0, ERR_REF_DELETED);
 | 
				
			||||||
 | 
					      //printf("INCR "); this->print();
 | 
				
			||||||
 | 
					      refcnt += 2;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void unref()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      //printf("DECR "); this->print();
 | 
				
			||||||
 | 
					      refcnt -= 2;
 | 
				
			||||||
 | 
					      if (refcnt == 0) {
 | 
				
			||||||
 | 
					        destroy();
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // A ref-counted collection of either primitive or ref-counted objects (String, Image,
 | 
				
			||||||
 | 
					  // user-defined record, another collection)
 | 
				
			||||||
 | 
					  class RefCollection
 | 
				
			||||||
 | 
					    : public RefObject
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    // 1 - collection of refs (need decr)
 | 
				
			||||||
 | 
					    // 2 - collection of strings (in fact we always have 3, never 2 alone)
 | 
				
			||||||
 | 
					    inline uint32_t getFlags() { return getVTable()->userdata; }
 | 
				
			||||||
 | 
					    inline bool isRef() { return getFlags() & 1; }
 | 
				
			||||||
 | 
					    inline bool isString() { return getFlags() & 2; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::vector<uint32_t> data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RefCollection(uint16_t f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline bool in_range(int x) {
 | 
				
			||||||
 | 
					      return (0 <= x && x < (int)data.size());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline int length() { return data.size(); }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void destroy();
 | 
				
			||||||
 | 
					    void print();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void push(uint32_t x);
 | 
				
			||||||
 | 
					    uint32_t getAt(int x);
 | 
				
			||||||
 | 
					    void removeAt(int x);
 | 
				
			||||||
 | 
					    void setAt(int x, uint32_t y);
 | 
				
			||||||
 | 
					    int indexOf(uint32_t x, int start);
 | 
				
			||||||
 | 
					    int removeElement(uint32_t x);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  struct MapEntry {
 | 
				
			||||||
 | 
					    uint32_t key;
 | 
				
			||||||
 | 
					    uint32_t val;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class RefMap
 | 
				
			||||||
 | 
					    : public RefObject
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    std::vector<MapEntry> data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RefMap();
 | 
				
			||||||
 | 
					    void destroy();
 | 
				
			||||||
 | 
					    void print();
 | 
				
			||||||
 | 
					    int findIdx(uint32_t key);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // A ref-counted, user-defined JS object.
 | 
				
			||||||
 | 
					  class RefRecord
 | 
				
			||||||
 | 
					    : public RefObject
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    // The object is allocated, so that there is space at the end for the fields.
 | 
				
			||||||
 | 
					    uint32_t fields[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RefRecord(uint16_t v) : RefObject(v) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    uint32_t ld(int idx);
 | 
				
			||||||
 | 
					    uint32_t ldref(int idx);
 | 
				
			||||||
 | 
					    void st(int idx, uint32_t v);
 | 
				
			||||||
 | 
					    void stref(int idx, uint32_t v);
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // these are needed when constructing vtables for user-defined classes
 | 
				
			||||||
 | 
					  void RefRecord_destroy(RefRecord *r);
 | 
				
			||||||
 | 
					  void RefRecord_print(RefRecord *r);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class RefAction;
 | 
				
			||||||
 | 
					  typedef uint32_t (*ActionCB)(uint32_t *captured, uint32_t arg0, uint32_t arg1, uint32_t arg2);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Ref-counted function pointer. It's currently always a ()=>void procedure pointer.
 | 
				
			||||||
 | 
					  class RefAction
 | 
				
			||||||
 | 
					    : public RefObject
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    // This is the same as for RefRecord.
 | 
				
			||||||
 | 
					    uint8_t len;
 | 
				
			||||||
 | 
					    uint8_t reflen;
 | 
				
			||||||
 | 
					    ActionCB func; // The function pointer
 | 
				
			||||||
 | 
					    // fields[] contain captured locals
 | 
				
			||||||
 | 
					    uint32_t fields[];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void destroy();
 | 
				
			||||||
 | 
					    void print();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    RefAction();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline void stCore(int idx, uint32_t v)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      //printf("ST [%d] = %d ", idx, v); this->print();
 | 
				
			||||||
 | 
					      intcheck(0 <= idx && idx < len, ERR_OUT_OF_BOUNDS, 10);
 | 
				
			||||||
 | 
					      intcheck(fields[idx] == 0, ERR_OUT_OF_BOUNDS, 11); // only one assignment permitted
 | 
				
			||||||
 | 
					      fields[idx] = v;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    inline uint32_t runCore(int arg0, int arg1, int arg2) // internal; use runAction*() functions
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      this->ref();
 | 
				
			||||||
 | 
					      uint32_t r = this->func(&this->fields[0], arg0, arg1, arg2);
 | 
				
			||||||
 | 
					      this->unref();
 | 
				
			||||||
 | 
					      return r;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // These two are used to represent locals written from inside inline functions
 | 
				
			||||||
 | 
					  class RefLocal
 | 
				
			||||||
 | 
					    : public RefObject
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    uint32_t v;
 | 
				
			||||||
 | 
					    void destroy();
 | 
				
			||||||
 | 
					    void print();
 | 
				
			||||||
 | 
					    RefLocal();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class RefRefLocal
 | 
				
			||||||
 | 
					    : public RefObject
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    uint32_t v;
 | 
				
			||||||
 | 
					    void destroy();
 | 
				
			||||||
 | 
					    void print();
 | 
				
			||||||
 | 
					    RefRefLocal();
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The ARM Thumb generator in the JavaScript code is parsing
 | 
				
			||||||
 | 
					// the hex file and looks for the magic numbers as present here.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Then it fetches function pointer addresses from there.
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					#define PXT_SHIMS_BEGIN \
 | 
				
			||||||
 | 
					namespace pxt { \
 | 
				
			||||||
 | 
					  const uint32_t functionsAndBytecode[] __attribute__((aligned(0x20))) = { \
 | 
				
			||||||
 | 
					    0x08010801, 0x42424242, 0x08010801, 0x8de9d83e,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PXT_SHIMS_END }; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma GCC diagnostic ignored "-Wpmf-conversions"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PXT_VTABLE_TO_INT(vt)  ((uint32_t)(vt) >> vtableShift)
 | 
				
			||||||
 | 
					#define PXT_VTABLE_BEGIN(classname, flags, iface) \
 | 
				
			||||||
 | 
					const VTable classname ## _vtable \
 | 
				
			||||||
 | 
					  __attribute__((aligned(1 << vtableShift))) \
 | 
				
			||||||
 | 
					  = { \
 | 
				
			||||||
 | 
					  sizeof(classname), \
 | 
				
			||||||
 | 
					  flags, \
 | 
				
			||||||
 | 
					  iface, \
 | 
				
			||||||
 | 
					  { \
 | 
				
			||||||
 | 
					    (void*)&classname::destroy, \
 | 
				
			||||||
 | 
					    (void*)&classname::print,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PXT_VTABLE_END } };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PXT_VTABLE_INIT(classname) \
 | 
				
			||||||
 | 
					  RefObject(PXT_VTABLE_TO_INT(&classname ## _vtable))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PXT_VTABLE_CTOR(classname) \
 | 
				
			||||||
 | 
					  PXT_VTABLE_BEGIN(classname, 0, 0) PXT_VTABLE_END \
 | 
				
			||||||
 | 
					  classname::classname() : PXT_VTABLE_INIT(classname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// vim: ts=2 sw=2 expandtab
 | 
				
			||||||
@@ -4,6 +4,10 @@
 | 
				
			|||||||
    "installedVersion": "tsmdvf",
 | 
					    "installedVersion": "tsmdvf",
 | 
				
			||||||
    "files": [
 | 
					    "files": [
 | 
				
			||||||
        "README.md",
 | 
					        "README.md",
 | 
				
			||||||
 | 
					        "ManagedBuffer.cpp",
 | 
				
			||||||
 | 
					        "ManagedBuffer.h",
 | 
				
			||||||
 | 
					        "pxt.cpp",
 | 
				
			||||||
 | 
					        "pxt.h",
 | 
				
			||||||
        "dal.d.ts",
 | 
					        "dal.d.ts",
 | 
				
			||||||
        "enums.d.ts",
 | 
					        "enums.d.ts",
 | 
				
			||||||
        "shims.d.ts",
 | 
					        "shims.d.ts",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -166,10 +166,10 @@
 | 
				
			|||||||
    },
 | 
					    },
 | 
				
			||||||
    "compileService": {
 | 
					    "compileService": {
 | 
				
			||||||
        "yottaTarget": "bbc-microbit-classic-gcc",
 | 
					        "yottaTarget": "bbc-microbit-classic-gcc",
 | 
				
			||||||
        "yottaCorePackage": "pxt-calliope-core",
 | 
					        "yottaCorePackage": "microbit",
 | 
				
			||||||
        "githubCorePackage": "microsoft/pxt-calliope-core",
 | 
					        "githubCorePackage": "calliope-mini/microbit",
 | 
				
			||||||
        "gittag": "v0.5.16",
 | 
					        "gittag": "v1.0.2-calliope",
 | 
				
			||||||
        "serviceId": "calliope"
 | 
					        "serviceId": "calliopemini"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "serial": {
 | 
					    "serial": {
 | 
				
			||||||
        "manufacturerFilter": "^mbed$",
 | 
					        "manufacturerFilter": "^mbed$",
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user