| Index: test/cctest/test-api.cc
|
| diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
|
| index 70ba21096d2489fee853f67e067247f145d83d18..8e58b60a60591ec7a0c23d6aa29871062bb12ae7 100644
|
| --- a/test/cctest/test-api.cc
|
| +++ b/test/cctest/test-api.cc
|
| @@ -5677,6 +5677,22 @@ THREADED_TEST(GlobalObjectInstanceProperties) {
|
| instance_template->Set(v8_str("f"),
|
| v8::FunctionTemplate::New(InstanceFunctionCallback));
|
|
|
| + // The script to check how Crankshaft compiles missing global function
|
| + // invocations. function g is not defined and should throw on call.
|
| + const char* script =
|
| + "function wrapper(call) {"
|
| + " var x = 0, y = 1;"
|
| + " for (var i = 0; i < 1000; i++) {"
|
| + " x += i * 100;"
|
| + " y += i * 100;"
|
| + " }"
|
| + " if (call) g();"
|
| + "}"
|
| + "for (var i = 0; i < 17; i++) wrapper(false);"
|
| + "var thrown = 0;"
|
| + "try { wrapper(true); } catch (e) { thrown = 1; };"
|
| + "thrown";
|
| +
|
| {
|
| LocalContext env(NULL, instance_template);
|
| // Hold on to the global object so it can be used again in another
|
| @@ -5687,6 +5703,8 @@ THREADED_TEST(GlobalObjectInstanceProperties) {
|
| CHECK_EQ(42, value->Int32Value());
|
| value = Script::Compile(v8_str("f()"))->Run();
|
| CHECK_EQ(12, value->Int32Value());
|
| + value = Script::Compile(v8_str(script))->Run();
|
| + CHECK_EQ(1, value->Int32Value());
|
| }
|
|
|
| {
|
| @@ -5696,6 +5714,48 @@ THREADED_TEST(GlobalObjectInstanceProperties) {
|
| CHECK_EQ(42, value->Int32Value());
|
| value = Script::Compile(v8_str("f()"))->Run();
|
| CHECK_EQ(12, value->Int32Value());
|
| + value = Script::Compile(v8_str(script))->Run();
|
| + CHECK_EQ(1, value->Int32Value());
|
| + }
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(CallKnownGlobalReceiver) {
|
| + v8::HandleScope handle_scope;
|
| +
|
| + Local<Value> global_object;
|
| +
|
| + Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
|
| + Local<ObjectTemplate> instance_template = t->InstanceTemplate();
|
| +
|
| + // The script to check that we leave global object not
|
| + // global object proxy on stack when we deoptimize from inside
|
| + // arguments evaluation.
|
| + // To provoke error we need to both force deoptimization
|
| + // from arguments evaluation and to force CallIC to take
|
| + // CallIC_Miss code path that can't cope with global proxy.
|
| + const char* script =
|
| + "function bar(x, y) { try { } finally { } }"
|
| + "function baz(x) { try { } finally { } }"
|
| + "function bom(x) { try { } finally { } }"
|
| + "function foo(x) { bar([x], bom(2)); }"
|
| + "for (var i = 0; i < 10000; i++) foo(1);"
|
| + "foo";
|
| +
|
| + Local<Value> foo;
|
| + {
|
| + LocalContext env(NULL, instance_template);
|
| + // Hold on to the global object so it can be used again in another
|
| + // environment initialization.
|
| + global_object = env->Global();
|
| + foo = Script::Compile(v8_str(script))->Run();
|
| + }
|
| +
|
| + {
|
| + // Create new environment reusing the global object.
|
| + LocalContext env(NULL, instance_template, global_object);
|
| + env->Global()->Set(v8_str("foo"), foo);
|
| + Local<Value> value = Script::Compile(v8_str("foo()"))->Run();
|
| }
|
| }
|
|
|
| @@ -8696,6 +8756,105 @@ THREADED_TEST(TurnOnAccessCheck) {
|
| }
|
|
|
|
|
| +v8::Handle<v8::String> a;
|
| +v8::Handle<v8::String> h;
|
| +
|
| +static bool NamedGetAccessBlockAandH(Local<v8::Object> obj,
|
| + Local<Value> name,
|
| + v8::AccessType type,
|
| + Local<Value> data) {
|
| + return !(name->Equals(a) || name->Equals(h));
|
| +}
|
| +
|
| +
|
| +THREADED_TEST(TurnOnAccessCheckAndRecompile) {
|
| + v8::HandleScope handle_scope;
|
| +
|
| + // Create an environment with access check to the global object disabled by
|
| + // default. When the registered access checker will block access to properties
|
| + // a and h
|
| + a = v8_str("a");
|
| + h = v8_str("h");
|
| + v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
|
| + global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH,
|
| + IndexedGetAccessBlocker,
|
| + v8::Handle<v8::Value>(),
|
| + false);
|
| + v8::Persistent<Context> context = Context::New(NULL, global_template);
|
| + Context::Scope context_scope(context);
|
| +
|
| + // Set up a property and a number of functions.
|
| + context->Global()->Set(v8_str("a"), v8_num(1));
|
| + static const char* source = "function f1() {return a;}"
|
| + "function f2() {return a;}"
|
| + "function g1() {return h();}"
|
| + "function g2() {return h();}"
|
| + "function h() {return 1;}";
|
| +
|
| + CompileRun(source);
|
| + Local<Function> f1;
|
| + Local<Function> f2;
|
| + Local<Function> g1;
|
| + Local<Function> g2;
|
| + Local<Function> h;
|
| + f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
|
| + f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
|
| + g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
|
| + g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
|
| + h = Local<Function>::Cast(context->Global()->Get(v8_str("h")));
|
| +
|
| + // Get the global object.
|
| + v8::Handle<v8::Object> global = context->Global();
|
| +
|
| + // Call f1 one time and f2 a number of times. This will ensure that f1 still
|
| + // uses the runtime system to retreive property a whereas f2 uses global load
|
| + // inline cache.
|
| + CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1)));
|
| + for (int i = 0; i < 4; i++) {
|
| + CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1)));
|
| + }
|
| +
|
| + // Same for g1 and g2.
|
| + CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1)));
|
| + for (int i = 0; i < 4; i++) {
|
| + CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1)));
|
| + }
|
| +
|
| + // Detach the global and turn on access check now blocking access to property
|
| + // a and function h.
|
| + context->DetachGlobal();
|
| + context->Global()->TurnOnAccessCheck();
|
| +
|
| + // Failing access check to property get results in undefined.
|
| + CHECK(f1->Call(global, 0, NULL)->IsUndefined());
|
| + CHECK(f2->Call(global, 0, NULL)->IsUndefined());
|
| +
|
| + // Failing access check to function call results in exception.
|
| + CHECK(g1->Call(global, 0, NULL).IsEmpty());
|
| + CHECK(g2->Call(global, 0, NULL).IsEmpty());
|
| +
|
| + // No failing access check when just returning a constant.
|
| + CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1)));
|
| +
|
| + // Now compile the source again. And get the newly compiled functions, except
|
| + // for h for which access is blocked.
|
| + CompileRun(source);
|
| + f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1")));
|
| + f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2")));
|
| + g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1")));
|
| + g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2")));
|
| + CHECK(context->Global()->Get(v8_str("h"))->IsUndefined());
|
| +
|
| + // Failing access check to property get results in undefined.
|
| + CHECK(f1->Call(global, 0, NULL)->IsUndefined());
|
| + CHECK(f2->Call(global, 0, NULL)->IsUndefined());
|
| +
|
| + // Failing access check to function call results in exception.
|
| + CHECK(g1->Call(global, 0, NULL).IsEmpty());
|
| + CHECK(g2->Call(global, 0, NULL).IsEmpty());
|
| +}
|
| +
|
| +
|
| // This test verifies that pre-compilation (aka preparsing) can be called
|
| // without initializing the whole VM. Thus we cannot run this test in a
|
| // multi-threaded setup.
|
| @@ -10547,7 +10706,9 @@ v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) {
|
|
|
|
|
| // Tests the C++ StackTrace API.
|
| -THREADED_TEST(CaptureStackTrace) {
|
| +// TODO(3074796): Reenable this as a THREADED_TEST once it passes.
|
| +// THREADED_TEST(CaptureStackTrace) {
|
| +TEST(CaptureStackTrace) {
|
| v8::HandleScope scope;
|
| v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test");
|
| Local<ObjectTemplate> templ = ObjectTemplate::New();
|
|
|