| 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;
|
|
|