Update V8 to r4851 as required by WebKit r61121
Change-Id: Ib01b7c8e38d5b82b254192fc06365aa5b85780c5
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 46eaccd..9123125 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -27,6 +27,8 @@
#include <limits.h>
+#define USE_NEW_QUERY_CALLBACKS
+
#include "v8.h"
#include "api.h"
@@ -610,6 +612,72 @@
}
+class TestAsciiResourceWithDisposeControl: public TestAsciiResource {
+ public:
+ static int dispose_calls;
+
+ TestAsciiResourceWithDisposeControl(const char* data, bool dispose)
+ : TestAsciiResource(data),
+ dispose_(dispose) { }
+
+ void Dispose() {
+ ++dispose_calls;
+ if (dispose_) delete this;
+ }
+ private:
+ bool dispose_;
+};
+
+
+int TestAsciiResourceWithDisposeControl::dispose_calls = 0;
+
+
+TEST(ExternalStringWithDisposeHandling) {
+ const char* c_source = "1 + 2 * 3";
+
+ // Use a stack allocated external string resource allocated object.
+ TestAsciiResource::dispose_count = 0;
+ TestAsciiResourceWithDisposeControl::dispose_calls = 0;
+ TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false);
+ {
+ v8::HandleScope scope;
+ LocalContext env;
+ Local<String> source = String::NewExternal(&res_stack);
+ Local<Script> script = Script::Compile(source);
+ Local<Value> value = script->Run();
+ CHECK(value->IsNumber());
+ CHECK_EQ(7, value->Int32Value());
+ v8::internal::Heap::CollectAllGarbage(false);
+ CHECK_EQ(0, TestAsciiResource::dispose_count);
+ }
+ v8::internal::CompilationCache::Clear();
+ v8::internal::Heap::CollectAllGarbage(false);
+ CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
+ CHECK_EQ(0, TestAsciiResource::dispose_count);
+
+ // Use a heap allocated external string resource allocated object.
+ TestAsciiResource::dispose_count = 0;
+ TestAsciiResourceWithDisposeControl::dispose_calls = 0;
+ TestAsciiResource* res_heap =
+ new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true);
+ {
+ v8::HandleScope scope;
+ LocalContext env;
+ Local<String> source = String::NewExternal(res_heap);
+ Local<Script> script = Script::Compile(source);
+ Local<Value> value = script->Run();
+ CHECK(value->IsNumber());
+ CHECK_EQ(7, value->Int32Value());
+ v8::internal::Heap::CollectAllGarbage(false);
+ CHECK_EQ(0, TestAsciiResource::dispose_count);
+ }
+ v8::internal::CompilationCache::Clear();
+ v8::internal::Heap::CollectAllGarbage(false);
+ CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls);
+ CHECK_EQ(1, TestAsciiResource::dispose_count);
+}
+
+
THREADED_TEST(StringConcat) {
{
v8::HandleScope scope;
@@ -1120,11 +1188,11 @@
}
-v8::Handle<v8::Boolean> CheckThisNamedPropertyQuery(Local<String> property,
+v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
CHECK(info.This()->Equals(bottom));
- return v8::Handle<v8::Boolean>();
+ return v8::Handle<v8::Integer>();
}
@@ -1221,13 +1289,13 @@
}
-static v8::Handle<v8::Boolean> PrePropertyHandlerHas(Local<String> key,
- const AccessorInfo&) {
+static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key,
+ const AccessorInfo&) {
if (v8_str("pre")->Equals(key)) {
- return v8::True();
+ return v8::Integer::New(v8::None);
}
- return v8::Handle<v8::Boolean>(); // do not intercept the call
+ return v8::Handle<v8::Integer>(); // do not intercept the call
}
@@ -1236,7 +1304,7 @@
v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New();
desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
0,
- PrePropertyHandlerHas);
+ PrePropertyHandlerQuery);
LocalContext env(NULL, desc->InstanceTemplate());
Script::Compile(v8_str(
"var pre = 'Object: pre'; var on = 'Object: on';"))->Run();
@@ -6245,12 +6313,25 @@
templ->SetAccessor(v8_str("y"), Return239);
LocalContext context;
context->Global()->Set(v8_str("o"), templ->NewInstance());
+
+ // Check the case when receiver and interceptor's holder
+ // are the same objects.
v8::Handle<Value> value = CompileRun(
"var result = 0;"
"for (var i = 0; i < 7; i++) {"
" result = o.y;"
"}");
CHECK_EQ(239, value->Int32Value());
+
+ // Check the case when interceptor's holder is in proto chain
+ // of receiver.
+ value = CompileRun(
+ "r = { __proto__: o };"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result = r.y;"
+ "}");
+ CHECK_EQ(239, value->Int32Value());
}
@@ -6265,6 +6346,8 @@
context->Global()->Set(v8_str("o"), templ_o->NewInstance());
context->Global()->Set(v8_str("p"), templ_p->NewInstance());
+ // Check the case when receiver and interceptor's holder
+ // are the same objects.
v8::Handle<Value> value = CompileRun(
"o.__proto__ = p;"
"var result = 0;"
@@ -6272,6 +6355,16 @@
" result = o.x + o.y;"
"}");
CHECK_EQ(239 + 42, value->Int32Value());
+
+ // Check the case when interceptor's holder is in proto chain
+ // of receiver.
+ value = CompileRun(
+ "r = { __proto__: o };"
+ "var result = 0;"
+ "for (var i = 0; i < 7; i++) {"
+ " result = r.x + r.y;"
+ "}");
+ CHECK_EQ(239 + 42, value->Int32Value());
}
@@ -7051,6 +7144,163 @@
}
+v8::Handle<Value> keyed_call_ic_function;
+
+static v8::Handle<Value> InterceptorKeyedCallICGetter(
+ Local<String> name, const AccessorInfo& info) {
+ ApiTestFuzzer::Fuzz();
+ if (v8_str("x")->Equals(name)) {
+ return keyed_call_ic_function;
+ }
+ return v8::Handle<Value>();
+}
+
+
+// Test the case when we stored cacheable lookup into
+// a stub, but the function name changed (to another cacheable function).
+THREADED_TEST(InterceptorKeyedCallICKeyChange1) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(
+ "proto = new Object();"
+ "proto.y = function(x) { return x + 1; };"
+ "proto.z = function(x) { return x - 1; };"
+ "o.__proto__ = proto;"
+ "var result = 0;"
+ "var method = 'y';"
+ "for (var i = 0; i < 10; i++) {"
+ " if (i == 5) { method = 'z'; };"
+ " result += o[method](41);"
+ "}");
+ CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
+}
+
+
+// Test the case when we stored cacheable lookup into
+// a stub, but the function name changed (and the new function is present
+// both before and after the interceptor in the prototype chain).
+THREADED_TEST(InterceptorKeyedCallICKeyChange2) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
+ LocalContext context;
+ context->Global()->Set(v8_str("proto1"), templ->NewInstance());
+ keyed_call_ic_function =
+ v8_compile("function f(x) { return x - 1; }; f")->Run();
+ v8::Handle<Value> value = CompileRun(
+ "o = new Object();"
+ "proto2 = new Object();"
+ "o.y = function(x) { return x + 1; };"
+ "proto2.y = function(x) { return x + 2; };"
+ "o.__proto__ = proto1;"
+ "proto1.__proto__ = proto2;"
+ "var result = 0;"
+ "var method = 'x';"
+ "for (var i = 0; i < 10; i++) {"
+ " if (i == 5) { method = 'y'; };"
+ " result += o[method](41);"
+ "}");
+ CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
+}
+
+
+// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit
+// on the global object.
+THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New();
+ templ->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ->NewInstance());
+ v8::Handle<Value> value = CompileRun(
+ "function inc(x) { return x + 1; };"
+ "inc(1);"
+ "function dec(x) { return x - 1; };"
+ "dec(1);"
+ "o.__proto__ = this;"
+ "this.__proto__.x = inc;"
+ "this.__proto__.y = dec;"
+ "var result = 0;"
+ "var method = 'x';"
+ "for (var i = 0; i < 10; i++) {"
+ " if (i == 5) { method = 'y'; };"
+ " result += o[method](41);"
+ "}");
+ CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
+}
+
+
+// Test the case when actual function to call sits on global object.
+THREADED_TEST(InterceptorKeyedCallICFromGlobal) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+ templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+
+ v8::Handle<Value> value = CompileRun(
+ "function len(x) { return x.length; };"
+ "o.__proto__ = this;"
+ "var m = 'parseFloat';"
+ "var result = 0;"
+ "for (var i = 0; i < 10; i++) {"
+ " if (i == 5) {"
+ " m = 'len';"
+ " saved_result = result;"
+ " };"
+ " result = o[m]('239');"
+ "}");
+ CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value());
+ CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value());
+}
+
+// Test the map transition before the interceptor.
+THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+ templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
+
+ v8::Handle<Value> value = CompileRun(
+ "var o = new Object();"
+ "o.__proto__ = proto;"
+ "o.method = function(x) { return x + 1; };"
+ "var m = 'method';"
+ "var result = 0;"
+ "for (var i = 0; i < 10; i++) {"
+ " if (i == 5) { o.method = function(x) { return x - 1; }; };"
+ " result += o[m](41);"
+ "}");
+ CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
+}
+
+
+// Test the map transition after the interceptor.
+THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) {
+ v8::HandleScope scope;
+ v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New();
+ templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+ LocalContext context;
+ context->Global()->Set(v8_str("o"), templ_o->NewInstance());
+
+ v8::Handle<Value> value = CompileRun(
+ "var proto = new Object();"
+ "o.__proto__ = proto;"
+ "proto.method = function(x) { return x + 1; };"
+ "var m = 'method';"
+ "var result = 0;"
+ "for (var i = 0; i < 10; i++) {"
+ " if (i == 5) { proto.method = function(x) { return x - 1; }; };"
+ " result += o[m](41);"
+ "}");
+ CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value());
+}
+
+
static int interceptor_call_count = 0;
static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name,
@@ -7203,6 +7453,18 @@
}
+THREADED_TEST(NamedPropertyHandlerGetterAttributes) {
+ v8::HandleScope scope;
+ v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New();
+ templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+ LocalContext env;
+ env->Global()->Set(v8_str("obj"),
+ templ->GetFunction()->NewInstance());
+ ExpectTrue("obj.x === 42");
+ ExpectTrue("!obj.propertyIsEnumerable('x')");
+}
+
+
static v8::Handle<Value> ParentGetter(Local<String> name,
const AccessorInfo& info) {
ApiTestFuzzer::Fuzz();
@@ -8236,6 +8498,30 @@
}
+// Verifies that the Handle<String> and const char* versions of the API produce
+// the same results (at least for one trivial case).
+TEST(PreCompileAPIVariationsAreSame) {
+ v8::V8::Initialize();
+ v8::HandleScope scope;
+
+ const char* cstring = "function foo(a) { return a+1; }";
+ v8::ScriptData* sd_from_cstring =
+ v8::ScriptData::PreCompile(cstring, i::StrLength(cstring));
+
+ TestAsciiResource* resource = new TestAsciiResource(cstring);
+ v8::ScriptData* sd_from_istring = v8::ScriptData::PreCompile(
+ v8::String::NewExternal(resource));
+
+ CHECK_EQ(sd_from_cstring->Length(), sd_from_istring->Length());
+ CHECK_EQ(0, memcmp(sd_from_cstring->Data(),
+ sd_from_istring->Data(),
+ sd_from_cstring->Length()));
+
+ delete sd_from_cstring;
+ delete sd_from_istring;
+}
+
+
// This tests that we do not allow dictionary load/call inline caches
// to use functions that have not yet been compiled. The potential
// problem of loading a function that has not yet been compiled can