Index: test/cctest/test-api.cc |
=================================================================== |
--- test/cctest/test-api.cc (revision 3095) |
+++ test/cctest/test-api.cc (working copy) |
@@ -25,6 +25,8 @@ |
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+#include <limits.h> |
+ |
#include "v8.h" |
#include "api.h" |
@@ -33,6 +35,7 @@ |
#include "snapshot.h" |
#include "platform.h" |
#include "top.h" |
+#include "utils.h" |
#include "cctest.h" |
static bool IsNaN(double x) { |
@@ -8039,6 +8042,324 @@ |
} |
+template <class ExternalArrayClass, class ElementType> |
+static void ExternalArrayTestHelper(v8::ExternalArrayType array_type, |
+ int64_t low, |
+ int64_t high) { |
+ v8::HandleScope scope; |
+ LocalContext context; |
+ const int kElementCount = 40; |
+ int element_size = 0; |
+ switch (array_type) { |
+ case v8::kExternalByteArray: |
+ case v8::kExternalUnsignedByteArray: |
+ element_size = 1; |
+ break; |
+ case v8::kExternalShortArray: |
+ case v8::kExternalUnsignedShortArray: |
+ element_size = 2; |
+ break; |
+ case v8::kExternalIntArray: |
+ case v8::kExternalUnsignedIntArray: |
+ case v8::kExternalFloatArray: |
+ element_size = 4; |
+ break; |
+ default: |
+ UNREACHABLE(); |
+ break; |
+ } |
+ ElementType* array_data = |
+ static_cast<ElementType*>(malloc(kElementCount * element_size)); |
+ i::Handle<ExternalArrayClass> array = |
+ i::Handle<ExternalArrayClass>::cast( |
+ i::Factory::NewExternalArray(kElementCount, array_type, array_data)); |
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification. |
+ for (int i = 0; i < kElementCount; i++) { |
+ array->set(i, static_cast<ElementType>(i)); |
+ } |
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification. |
+ for (int i = 0; i < kElementCount; i++) { |
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i))); |
+ CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i])); |
+ } |
+ |
+ v8::Handle<v8::Object> obj = v8::Object::New(); |
+ i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); |
+ // Set the elements to be the external array. |
+ obj->SetIndexedPropertiesToExternalArrayData(array_data, |
+ array_type, |
+ kElementCount); |
+ CHECK_EQ(1, static_cast<int>(jsobj->GetElement(1)->Number())); |
+ obj->Set(v8_str("field"), v8::Int32::New(1503)); |
+ context->Global()->Set(v8_str("ext_array"), obj); |
+ v8::Handle<v8::Value> result = CompileRun("ext_array.field"); |
+ CHECK_EQ(1503, result->Int32Value()); |
+ result = CompileRun("ext_array[1]"); |
+ CHECK_EQ(1, result->Int32Value()); |
+ |
+ // Check pass through of assigned smis |
+ result = CompileRun("var sum = 0;" |
+ "for (var i = 0; i < 8; i++) {" |
+ " sum += ext_array[i] = ext_array[i] = -i;" |
+ "}" |
+ "sum;"); |
+ CHECK_EQ(-28, result->Int32Value()); |
+ |
+ // Check assigned smis |
+ result = CompileRun("for (var i = 0; i < 8; i++) {" |
+ " ext_array[i] = i;" |
+ "}" |
+ "var sum = 0;" |
+ "for (var i = 0; i < 8; i++) {" |
+ " sum += ext_array[i];" |
+ "}" |
+ "sum;"); |
+ CHECK_EQ(28, result->Int32Value()); |
+ |
+ // Check assigned smis in reverse order |
+ result = CompileRun("for (var i = 8; --i >= 0; ) {" |
+ " ext_array[i] = i;" |
+ "}" |
+ "var sum = 0;" |
+ "for (var i = 0; i < 8; i++) {" |
+ " sum += ext_array[i];" |
+ "}" |
+ "sum;"); |
+ CHECK_EQ(28, result->Int32Value()); |
+ |
+ // Check pass through of assigned HeapNumbers |
+ result = CompileRun("var sum = 0;" |
+ "for (var i = 0; i < 16; i+=2) {" |
+ " sum += ext_array[i] = ext_array[i] = (-i * 0.5);" |
+ "}" |
+ "sum;"); |
+ CHECK_EQ(-28, result->Int32Value()); |
+ |
+ // Check assigned HeapNumbers |
+ result = CompileRun("for (var i = 0; i < 16; i+=2) {" |
+ " ext_array[i] = (i * 0.5);" |
+ "}" |
+ "var sum = 0;" |
+ "for (var i = 0; i < 16; i+=2) {" |
+ " sum += ext_array[i];" |
+ "}" |
+ "sum;"); |
+ CHECK_EQ(28, result->Int32Value()); |
+ |
+ // Check assigned HeapNumbers in reverse order |
+ result = CompileRun("for (var i = 14; i >= 0; i-=2) {" |
+ " ext_array[i] = (i * 0.5);" |
+ "}" |
+ "var sum = 0;" |
+ "for (var i = 0; i < 16; i+=2) {" |
+ " sum += ext_array[i];" |
+ "}" |
+ "sum;"); |
+ CHECK_EQ(28, result->Int32Value()); |
+ |
+ i::ScopedVector<char> test_buf(1024); |
+ |
+ // Check legal boundary conditions. |
+ // The repeated loads and stores ensure the ICs are exercised. |
+ const char* boundary_program = |
+ "var res = 0;" |
+ "for (var i = 0; i < 16; i++) {" |
+ " ext_array[i] = %lld;" |
+ " if (i > 8) {" |
+ " res = ext_array[i];" |
+ " }" |
+ "}" |
+ "res;"; |
+ i::OS::SNPrintF(test_buf, |
+ boundary_program, |
+ low); |
+ result = CompileRun(test_buf.start()); |
+ CHECK_EQ(low, result->IntegerValue()); |
+ |
+ i::OS::SNPrintF(test_buf, |
+ boundary_program, |
+ high); |
+ result = CompileRun(test_buf.start()); |
+ CHECK_EQ(high, result->IntegerValue()); |
+ |
+ // Check misprediction of type in IC. |
+ result = CompileRun("var tmp_array = ext_array;" |
+ "var sum = 0;" |
+ "for (var i = 0; i < 8; i++) {" |
+ " tmp_array[i] = i;" |
+ " sum += tmp_array[i];" |
+ " if (i == 4) {" |
+ " tmp_array = {};" |
+ " }" |
+ "}" |
+ "sum;"); |
+ i::Heap::CollectAllGarbage(false); // Force GC to trigger verification. |
+ CHECK_EQ(28, result->Int32Value()); |
+ |
+ // Check out-of-range loads. |
+ result = CompileRun("var caught_exception = false;" |
+ "try {" |
+ " ext_array[-1];" |
+ "} catch (e) {" |
+ " caught_exception = true;" |
+ "}" |
+ "caught_exception;"); |
+ CHECK_EQ(true, result->BooleanValue()); |
+ |
+ i::OS::SNPrintF(test_buf, |
+ "var caught_exception = false;" |
+ "try {" |
+ " ext_array[%d];" |
+ "} catch (e) {" |
+ " caught_exception = true;" |
+ "}" |
+ "caught_exception;", |
+ kElementCount); |
+ result = CompileRun(test_buf.start()); |
+ CHECK_EQ(true, result->BooleanValue()); |
+ |
+ // Check out-of-range stores. |
+ result = CompileRun("var caught_exception = false;" |
+ "try {" |
+ " ext_array[-1] = 1;" |
+ "} catch (e) {" |
+ " caught_exception = true;" |
+ "}" |
+ "caught_exception;"); |
+ CHECK_EQ(true, result->BooleanValue()); |
+ |
+ i::OS::SNPrintF(test_buf, |
+ "var caught_exception = false;" |
+ "try {" |
+ " ext_array[%d] = 1;" |
+ "} catch (e) {" |
+ " caught_exception = true;" |
+ "}" |
+ "caught_exception;", |
+ kElementCount); |
+ result = CompileRun(test_buf.start()); |
+ CHECK_EQ(true, result->BooleanValue()); |
+ |
+ // TODO(kbr): check what happens during IC misses on the type of the object. |
+ // Re-assign array object halfway through a loop. |
+ |
+ // Check other boundary conditions, values and operations. |
+ result = CompileRun("for (var i = 0; i < 8; i++) {" |
+ " ext_array[7] = undefined;" |
+ "}" |
+ "ext_array[7];"); |
+ CHECK_EQ(0, result->Int32Value()); |
+ CHECK_EQ(0, static_cast<int>(jsobj->GetElement(7)->Number())); |
+ |
+ result = CompileRun("for (var i = 0; i < 8; i++) {" |
+ " ext_array[6] = '2.3';" |
+ "}" |
+ "ext_array[6];"); |
+ CHECK_EQ(2, result->Int32Value()); |
+ CHECK_EQ(2, static_cast<int>(jsobj->GetElement(6)->Number())); |
+ |
+ // Result for storing NaNs and +/-Infinity isn't defined for these |
+ // types; they do not have the clamping behavior CanvasPixelArray |
+ // specifies. |
+ |
+ result = CompileRun("ext_array[3] = 33;" |
+ "delete ext_array[3];" |
+ "ext_array[3];"); |
+ CHECK_EQ(33, result->Int32Value()); |
+ |
+ result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;" |
+ "ext_array[2] = 12; ext_array[3] = 13;" |
+ "ext_array.__defineGetter__('2'," |
+ "function() { return 120; });" |
+ "ext_array[2];"); |
+ CHECK_EQ(12, result->Int32Value()); |
+ |
+ result = CompileRun("var js_array = new Array(40);" |
+ "js_array[0] = 77;" |
+ "js_array;"); |
+ CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); |
+ |
+ result = CompileRun("ext_array[1] = 23;" |
+ "ext_array.__proto__ = [];" |
+ "js_array.__proto__ = ext_array;" |
+ "js_array.concat(ext_array);"); |
+ CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); |
+ CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); |
+ |
+ result = CompileRun("ext_array[1] = 23;"); |
+ CHECK_EQ(23, result->Int32Value()); |
+ |
+ free(array_data); |
+} |
+ |
+ |
+THREADED_TEST(ExternalByteArray) { |
+ ExternalArrayTestHelper<v8::internal::ExternalByteArray, int8_t>( |
+ v8::kExternalByteArray, |
+ -128, |
+ 127); |
+} |
+ |
+ |
+THREADED_TEST(ExternalUnsignedByteArray) { |
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedByteArray, uint8_t>( |
+ v8::kExternalUnsignedByteArray, |
+ 0, |
+ 255); |
+} |
+ |
+ |
+THREADED_TEST(ExternalShortArray) { |
+ ExternalArrayTestHelper<v8::internal::ExternalShortArray, int16_t>( |
+ v8::kExternalShortArray, |
+ -32768, |
+ 32767); |
+} |
+ |
+ |
+THREADED_TEST(ExternalUnsignedShortArray) { |
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedShortArray, uint16_t>( |
+ v8::kExternalUnsignedShortArray, |
+ 0, |
+ 65535); |
+} |
+ |
+ |
+THREADED_TEST(ExternalIntArray) { |
+ ExternalArrayTestHelper<v8::internal::ExternalIntArray, int32_t>( |
+ v8::kExternalIntArray, |
+ INT_MIN, // -2147483648 |
+ INT_MAX); // 2147483647 |
+} |
+ |
+ |
+THREADED_TEST(ExternalUnsignedIntArray) { |
+ ExternalArrayTestHelper<v8::internal::ExternalUnsignedIntArray, uint32_t>( |
+ v8::kExternalUnsignedIntArray, |
+ 0, |
+ UINT_MAX); // 4294967295 |
+} |
+ |
+ |
+THREADED_TEST(ExternalFloatArray) { |
+ ExternalArrayTestHelper<v8::internal::ExternalFloatArray, float>( |
+ v8::kExternalFloatArray, |
+ -500, |
+ 500); |
+} |
+ |
+ |
+THREADED_TEST(ExternalArrays) { |
+ TestExternalByteArray(); |
+ TestExternalUnsignedByteArray(); |
+ TestExternalShortArray(); |
+ TestExternalUnsignedShortArray(); |
+ TestExternalIntArray(); |
+ TestExternalUnsignedIntArray(); |
+ TestExternalFloatArray(); |
+} |
+ |
+ |
THREADED_TEST(ScriptContextDependence) { |
v8::HandleScope scope; |
LocalContext c1; |