mirror of
				https://github.com/tc39/test262.git
				synced 2025-10-31 11:44:31 +01:00 
			
		
		
		
	* [javascriptcore-test262-automation] changes from git@github.com:WebKit/webkit.git at sha 949e26452cfa153a7f4afe593da97e2fe9e1b706 on Tue Jul 03 2018 14:35:15 GMT-0400 (Eastern Daylight Time)
		
			
				
	
	
		
			340 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			340 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /*
 | |
|  * Copyright (C) 2016 Apple Inc. All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 | |
|  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 | |
|  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 | |
|  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | |
|  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | |
|  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | |
|  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 | |
|  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
|  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| import * as assert from 'assert.js';
 | |
| import * as WASM from 'WASM.js';
 | |
| 
 | |
| const _initialAllocationSize = 1024;
 | |
| const _growAllocationSize = allocated => allocated * 2;
 | |
| 
 | |
| export const varuint32Min = 0;
 | |
| export const varint7Min = -0b1000000;
 | |
| export const varint7Max = 0b111111;
 | |
| export const varuint7Max = 0b1111111;
 | |
| export const varuint32Max = ((((1 << 31) >>> 0) - 1) * 2) + 1;
 | |
| export const varint32Min = -((1 << 31) >>> 0);
 | |
| export const varint32Max = ((1 << 31) - 1) >>> 0;
 | |
| export const varBitsMax = 5;
 | |
| 
 | |
| const _getterRangeCheck = (llb, at, size) => {
 | |
|     if (0 > at || at + size > llb._used)
 | |
|         throw new RangeError(`[${at}, ${at + size}) is out of buffer range [0, ${llb._used})`);
 | |
| };
 | |
| 
 | |
| const _hexdump = (buf, size) => {
 | |
|     let s = "";
 | |
|     const width = 16;
 | |
|     const base = 16;
 | |
|     for (let row = 0; row * width < size; ++row) {
 | |
|         const address = (row * width).toString(base);
 | |
|         s += "0".repeat(8 - address.length) + address;
 | |
|         let chars = "";
 | |
|         for (let col = 0; col !== width; ++col) {
 | |
|             const idx = row * width + col;
 | |
|             if (idx < size) {
 | |
|                 const byte = buf[idx];
 | |
|                 const bytestr = byte.toString(base);
 | |
|                 s += " " + (bytestr.length === 1 ? "0" + bytestr : bytestr);
 | |
|                 chars += 0x20 <= byte && byte < 0x7F ? String.fromCharCode(byte) : "·";
 | |
|             } else {
 | |
|                 s += "   ";
 | |
|                 chars += " ";
 | |
|             }
 | |
|         }
 | |
|         s+= "  |" + chars + "|\n";
 | |
|     }
 | |
|     return s;
 | |
| };
 | |
| 
 | |
| export default class LowLevelBinary {
 | |
|     constructor() {
 | |
|         this._buf = new Uint8Array(_initialAllocationSize);
 | |
|         this._used = 0;
 | |
|     }
 | |
| 
 | |
|     newPatchable(type) { return new PatchableLowLevelBinary(type, this); }
 | |
| 
 | |
|     // Utilities.
 | |
|     get() { return this._buf; }
 | |
|     trim() { this._buf = this._buf.slice(0, this._used); }
 | |
| 
 | |
|     hexdump() { return _hexdump(this._buf, this._used); }
 | |
|     _maybeGrow(bytes) {
 | |
|         const allocated = this._buf.length;
 | |
|         if (allocated - this._used < bytes) {
 | |
|             let buf = new Uint8Array(_growAllocationSize(allocated));
 | |
|             buf.set(this._buf);
 | |
|             this._buf = buf;
 | |
|         }
 | |
|     }
 | |
|     _push8(v) { this._buf[this._used] = v & 0xFF; this._used += 1; }
 | |
| 
 | |
|     // Data types.
 | |
|     uint8(v) {
 | |
|         if ((v & 0xFF) >>> 0 !== v)
 | |
|             throw new RangeError(`Invalid uint8 ${v}`);
 | |
|         this._maybeGrow(1);
 | |
|         this._push8(v);
 | |
|     }
 | |
|     uint16(v) {
 | |
|         if ((v & 0xFFFF) >>> 0 !== v)
 | |
|             throw new RangeError(`Invalid uint16 ${v}`);
 | |
|         this._maybeGrow(2);
 | |
|         this._push8(v);
 | |
|         this._push8(v >>> 8);
 | |
|     }
 | |
|     uint24(v) {
 | |
|         if ((v & 0xFFFFFF) >>> 0 !== v)
 | |
|             throw new RangeError(`Invalid uint24 ${v}`);
 | |
|         this._maybeGrow(3);
 | |
|         this._push8(v);
 | |
|         this._push8(v >>> 8);
 | |
|         this._push8(v >>> 16);
 | |
|     }
 | |
|     uint32(v) {
 | |
|         if ((v & 0xFFFFFFFF) >>> 0 !== v)
 | |
|             throw new RangeError(`Invalid uint32 ${v}`);
 | |
|         this._maybeGrow(4);
 | |
|         this._push8(v);
 | |
|         this._push8(v >>> 8);
 | |
|         this._push8(v >>> 16);
 | |
|         this._push8(v >>> 24);
 | |
|     }
 | |
|     float(v) {
 | |
|         if (isNaN(v))
 | |
|             throw new RangeError("unimplemented, NaNs");
 | |
|         // Unfortunately, we cannot just view the actual buffer as a Float32Array since it needs to be 4 byte aligned
 | |
|         let buffer = new ArrayBuffer(4);
 | |
|         let floatView = new Float32Array(buffer);
 | |
|         let int8View = new Uint8Array(buffer);
 | |
|         floatView[0] = v;
 | |
|         for (let byte of int8View)
 | |
|             this._push8(byte);
 | |
|     }
 | |
| 
 | |
|     double(v) {
 | |
|         if (isNaN(v))
 | |
|             throw new RangeError("unimplemented, NaNs");
 | |
|         // Unfortunately, we cannot just view the actual buffer as a Float64Array since it needs to be 4 byte aligned
 | |
|         let buffer = new ArrayBuffer(8);
 | |
|         let floatView = new Float64Array(buffer);
 | |
|         let int8View = new Uint8Array(buffer);
 | |
|         floatView[0] = v;
 | |
|         for (let byte of int8View)
 | |
|             this._push8(byte);
 | |
|     }
 | |
| 
 | |
|     varuint32(v) {
 | |
|         assert.isNumber(v);
 | |
|         if (v < varuint32Min || varuint32Max < v)
 | |
|             throw new RangeError(`Invalid varuint32 ${v} range is [${varuint32Min}, ${varuint32Max}]`);
 | |
|         while (v >= 0x80) {
 | |
|             this.uint8(0x80 | (v & 0x7F));
 | |
|             v >>>= 7;
 | |
|         }
 | |
|         this.uint8(v);
 | |
|     }
 | |
|     varint32(v) {
 | |
|         assert.isNumber(v);
 | |
|         if (v < varint32Min || varint32Max < v)
 | |
|             throw new RangeError(`Invalid varint32 ${v} range is [${varint32Min}, ${varint32Max}]`);
 | |
|         do {
 | |
|             const b = v & 0x7F;
 | |
|             v >>= 7;
 | |
|             if ((v === 0 && ((b & 0x40) === 0)) || (v === -1 && ((b & 0x40) === 0x40))) {
 | |
|                 this.uint8(b & 0x7F);
 | |
|                 break;
 | |
|             }
 | |
|             this.uint8(0x80 | b);
 | |
|         } while (true);
 | |
|     }
 | |
|     varuint64(v) {
 | |
|         assert.isNumber(v);
 | |
|         if (v < varuint32Min || varuint32Max < v)
 | |
|             throw new RangeError(`unimplemented: varuint64 larger than 32-bit`);
 | |
|         this.varuint32(v); // FIXME implement 64-bit var{u}int https://bugs.webkit.org/show_bug.cgi?id=163420
 | |
|     }
 | |
|     varint64(v) {
 | |
|         assert.isNumber(v);
 | |
|         if (v < varint32Min || varint32Max < v)
 | |
|             throw new RangeError(`unimplemented: varint64 larger than 32-bit`);
 | |
|         this.varint32(v); // FIXME implement 64-bit var{u}int https://bugs.webkit.org/show_bug.cgi?id=163420
 | |
|     }
 | |
|     varuint1(v) {
 | |
|         if (v !== 0 && v !== 1)
 | |
|             throw new RangeError(`Invalid varuint1 ${v} range is [0, 1]`);
 | |
|         this.varuint32(v);
 | |
|     }
 | |
|     varint7(v) {
 | |
|         if (v < varint7Min || varint7Max < v)
 | |
|             throw new RangeError(`Invalid varint7 ${v} range is [${varint7Min}, ${varint7Max}]`);
 | |
|         this.varint32(v);
 | |
|     }
 | |
|     varuint7(v) {
 | |
|         if (v < varuint32Min || varuint7Max < v)
 | |
|             throw new RangeError(`Invalid varuint7 ${v} range is [${varuint32Min}, ${varuint7Max}]`);
 | |
|         this.varuint32(v);
 | |
|     }
 | |
|     block_type(v) {
 | |
|         if (!WASM.isValidBlockType(v))
 | |
|             throw new Error(`Invalid block type ${v}`);
 | |
|         this.varint7(WASM.typeValue[v]);
 | |
|     }
 | |
|     string(str) {
 | |
|         let patch = this.newPatchable("varuint32");
 | |
|         for (const char of str) {
 | |
|             // Encode UTF-8 2003 code points.
 | |
|             const code = char.codePointAt();
 | |
|             if (code <= 0x007F) {
 | |
|                 const utf8 = code;
 | |
|                 patch.uint8(utf8);
 | |
|             } else if (code <= 0x07FF) {
 | |
|                 const utf8 = 0x80C0 | ((code & 0x7C0) >> 6) | ((code & 0x3F) << 8);
 | |
|                 patch.uint16(utf8);
 | |
|             } else if (code <= 0xFFFF) {
 | |
|                 const utf8 = 0x8080E0 | ((code & 0xF000) >> 12) | ((code & 0xFC0) << 2) | ((code & 0x3F) << 16);
 | |
|                 patch.uint24(utf8);
 | |
|             } else if (code <= 0x10FFFF) {
 | |
|                 const utf8 = (0x808080F0 | ((code & 0x1C0000) >> 18) | ((code & 0x3F000) >> 4) | ((code & 0xFC0) << 10) | ((code & 0x3F) << 24)) >>> 0;
 | |
|                 patch.uint32(utf8);
 | |
|             } else
 | |
|                 throw new Error(`Unexpectedly large UTF-8 character code point '${char}' 0x${code.toString(16)}`);
 | |
|         }
 | |
|         patch.apply();
 | |
|     }
 | |
| 
 | |
|     // Getters.
 | |
|     getSize() { return this._used; }
 | |
|     getUint8(at) {
 | |
|         _getterRangeCheck(this, at, 1);
 | |
|         return this._buf[at];
 | |
|     }
 | |
|     getUint16(at) {
 | |
|         _getterRangeCheck(this, at, 2);
 | |
|         return this._buf[at] | (this._buf[at + 1] << 8);
 | |
|     }
 | |
|     getUint24(at) {
 | |
|         _getterRangeCheck(this, at, 3);
 | |
|         return this._buf[at] | (this._buf[at + 1] << 8) | (this._buf[at + 2] << 16);
 | |
|     }
 | |
|     getUint32(at) {
 | |
|         _getterRangeCheck(this, at, 4);
 | |
|         return (this._buf[at] | (this._buf[at + 1] << 8) | (this._buf[at + 2] << 16) | (this._buf[at + 3] << 24)) >>> 0;
 | |
|     }
 | |
|     getVaruint32(at) {
 | |
|         let v = 0;
 | |
|         let shift = 0;
 | |
|         let byte = 0;
 | |
|         do {
 | |
|             byte = this.getUint8(at++);
 | |
|             ++read;
 | |
|             v = (v | ((byte & 0x7F) << shift) >>> 0) >>> 0;
 | |
|             shift += 7;
 | |
|         } while ((byte & 0x80) !== 0);
 | |
|         if (shift - 7 > 32) throw new RangeError(`Shifting too much at ${at}`);
 | |
|         if ((shift == 35) && ((byte & 0xF0) != 0)) throw new Error(`Unexpected non-significant varuint32 bits in last byte 0x${byte.toString(16)}`);
 | |
|         return { value: v, next: at };
 | |
|     }
 | |
|     getVarint32(at) {
 | |
|         let v = 0;
 | |
|         let shift = 0;
 | |
|         let byte = 0;
 | |
|         do {
 | |
|             byte = this.getUint8(at++);
 | |
|             v = (v | ((byte & 0x7F) << shift) >>> 0) >>> 0;
 | |
|             shift += 7;
 | |
|         } while ((byte & 0x80) !== 0);
 | |
|         if (shift - 7 > 32) throw new RangeError(`Shifting too much at ${at}`);
 | |
|         if ((shift == 35) && (((byte << 26) >> 30) != ((byte << 25) >> 31))) throw new Error(`Unexpected non-significant varint32 bits in last byte 0x${byte.toString(16)}`);
 | |
|         if ((byte & 0x40) === 0x40) {
 | |
|             const sext = shift < 32 ? 32 - shift : 0;
 | |
|             v = (v << sext) >> sext;
 | |
|         }
 | |
|         return { value: v, next: at };
 | |
|     }
 | |
|     getVaruint1(at) {
 | |
|         const res = this.getVaruint32(at);
 | |
|         if (res.value !== 0 && res.value !== 1) throw new Error(`Expected a varuint1, got value ${res.value}`);
 | |
|         return res;
 | |
|     }
 | |
|     getVaruint7(at) {
 | |
|         const res = this.getVaruint32(at);
 | |
|         if (res.value > varuint7Max) throw new Error(`Expected a varuint7, got value ${res.value}`);
 | |
|         return res;
 | |
|     }
 | |
|     getString(at) {
 | |
|         const size = this.getVaruint32(at);
 | |
|         const last = size.next + size.value;
 | |
|         let i = size.next;
 | |
|         let str = "";
 | |
|         while (i < last) {
 | |
|             // Decode UTF-8 2003 code points.
 | |
|             const peek = this.getUint8(i);
 | |
|             let code;
 | |
|             if ((peek & 0x80) === 0x0) {
 | |
|                 const utf8 = this.getUint8(i);
 | |
|                 assert.eq(utf8 & 0x80, 0x00);
 | |
|                 i += 1;
 | |
|                 code = utf8;
 | |
|             } else if ((peek & 0xE0) === 0xC0) {
 | |
|                 const utf8 = this.getUint16(i);
 | |
|                 assert.eq(utf8 & 0xC0E0, 0x80C0);
 | |
|                 i += 2;
 | |
|                 code = ((utf8 & 0x1F) << 6) | ((utf8 & 0x3F00) >> 8);
 | |
|             } else if ((peek & 0xF0) === 0xE0) {
 | |
|                 const utf8 = this.getUint24(i);
 | |
|                 assert.eq(utf8 & 0xC0C0F0, 0x8080E0);
 | |
|                 i += 3;
 | |
|                 code = ((utf8 & 0xF) << 12) | ((utf8 & 0x3F00) >> 2) | ((utf8 & 0x3F0000) >> 16);
 | |
|             } else if ((peek & 0xF8) === 0xF0) {
 | |
|                 const utf8 = this.getUint32(i);
 | |
|                 assert.eq((utf8 & 0xC0C0C0F8) | 0, 0x808080F0 | 0);
 | |
|                 i += 4;
 | |
|                 code = ((utf8 & 0x7) << 18) | ((utf8 & 0x3F00) << 4) | ((utf8 & 0x3F0000) >> 10) | ((utf8 & 0x3F000000) >> 24);
 | |
|             } else
 | |
|                 throw new Error(`Unexpectedly large UTF-8 initial byte 0x${peek.toString(16)}`);
 | |
|             str += String.fromCodePoint(code);
 | |
|         }
 | |
|         if (i !== last)
 | |
|             throw new Error(`String decoding read up to ${i}, expected ${last}, UTF-8 decoding was too greedy`);
 | |
|         return str;
 | |
|     }
 | |
| };
 | |
| 
 | |
| class PatchableLowLevelBinary extends LowLevelBinary {
 | |
|     constructor(type, lowLevelBinary) {
 | |
|         super();
 | |
|         this.type = type;
 | |
|         this.target = lowLevelBinary;
 | |
|         this._buffered_bytes = 0;
 | |
|     }
 | |
|     _push8(v) { ++this._buffered_bytes; super._push8(v); }
 | |
|     apply() {
 | |
|         this.target[this.type](this._buffered_bytes);
 | |
|         for (let i = 0; i < this._buffered_bytes; ++i)
 | |
|             this.target.uint8(this._buf[i]);
 | |
|     }
 | |
| };
 |