From c6c55a69a93db86b563f9d829c12e72b61593b45 Mon Sep 17 00:00:00 2001 From: "vitalyr@chromium.org" Date: Fri, 17 Sep 2010 09:56:47 +0000 Subject: [PATCH] Fix direct loading of global function prototypes: We must also check the current context has not changed. The bug reported by Florian. Review URL: http://codereview.chromium.org/3410014 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@5483 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/stub-cache-arm.cc | 19 +++++++++---- src/ia32/stub-cache-ia32.cc | 18 ++++++++---- src/stub-cache.h | 12 ++++---- src/x64/stub-cache-x64.cc | 19 +++++++++---- test/cctest/test-api.cc | 69 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+), 23 deletions(-) diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 0da5f64..ab33884 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -266,7 +266,12 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype) { + MacroAssembler* masm, int index, Register prototype, Label* miss) { + // Check we're still in the same context. + __ ldr(prototype, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_INDEX))); + __ Move(ip, Top::global()); + __ cmp(prototype, ip); + __ b(ne, miss); // Get the global function with the given index. JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); // Load its initial map. The global functions all have initial maps. @@ -1434,7 +1439,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall( // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - r0); + r0, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r1, r3, r4, name, &miss); @@ -1505,7 +1511,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - r0); + r0, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r1, r3, r4, name, &miss); @@ -1705,7 +1712,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ b(hs, &miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::STRING_FUNCTION_INDEX, r0); + masm(), Context::STRING_FUNCTION_INDEX, r0, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, r4, name, &miss); } @@ -1725,7 +1732,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::NUMBER_FUNCTION_INDEX, r0); + masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, r4, name, &miss); } @@ -1748,7 +1755,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::BOOLEAN_FUNCTION_INDEX, r0); + masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, r1, r4, name, &miss); } diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index 828e71a..a71c332 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -265,7 +265,11 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype) { + MacroAssembler* masm, int index, Register prototype, Label* miss) { + // Check we're still in the same context. + __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)), + Top::global()); + __ j(not_equal, miss); // Get the global function with the given index. JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); // Load its initial map. The global functions all have initial maps. @@ -1626,7 +1630,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall( // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - eax); + eax, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); @@ -1695,7 +1700,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - eax); + eax, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); @@ -1894,7 +1900,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ j(above_equal, &miss, not_taken); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::STRING_FUNCTION_INDEX, eax); + masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); } @@ -1914,7 +1920,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::NUMBER_FUNCTION_INDEX, eax); + masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); } @@ -1935,7 +1941,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::BOOLEAN_FUNCTION_INDEX, eax); + masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, ebx, edx, edi, name, &miss); } diff --git a/src/stub-cache.h b/src/stub-cache.h index 388bb52..7e44fd0 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -370,13 +370,15 @@ class StubCompiler BASE_EMBEDDED { Register prototype); // Generates prototype loading code that uses the objects from the - // context we were in when this function was called. This ties the - // generated code to a particular context and so must not be used in - // cases where the generated code is not allowed to have references - // to objects from a context. + // context we were in when this function was called. If the context + // has changed, a jump to miss is performed. This ties the generated + // code to a particular context and so must not be used in cases + // where the generated code is not allowed to have references to + // objects from a context. static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, int index, - Register prototype); + Register prototype, + Label* miss); static void GenerateFastPropertyLoad(MacroAssembler* masm, Register dst, Register src, diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc index 765a90c..ab61390 100644 --- a/src/x64/stub-cache-x64.cc +++ b/src/x64/stub-cache-x64.cc @@ -216,7 +216,12 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( - MacroAssembler* masm, int index, Register prototype) { + MacroAssembler* masm, int index, Register prototype, Label* miss) { + // Check we're still in the same context. + __ Move(prototype, Top::global()); + __ cmpq(Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)), + prototype); + __ j(not_equal, miss); // Get the global function with the given index. JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); // Load its initial map. The global functions all have initial maps. @@ -964,7 +969,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ j(above_equal, &miss); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::STRING_FUNCTION_INDEX, rax); + masm(), Context::STRING_FUNCTION_INDEX, rax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, rbx, rdx, rdi, name, &miss); } @@ -983,7 +988,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::NUMBER_FUNCTION_INDEX, rax); + masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, rbx, rdx, rdi, name, &miss); } @@ -1004,7 +1009,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, __ bind(&fast); // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype( - masm(), Context::BOOLEAN_FUNCTION_INDEX, rax); + masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss); CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, rbx, rdx, rdi, name, &miss); } @@ -1358,7 +1363,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - rax); + rax, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, rbx, rdx, rdi, name, &miss); @@ -1429,7 +1435,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall( // Check that the maps starting from the prototype haven't changed. GenerateDirectLoadGlobalFunctionPrototype(masm(), Context::STRING_FUNCTION_INDEX, - rax); + rax, + &miss); ASSERT(object != holder); CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, rbx, rdx, rdi, name, &miss); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 2b50db7..d186670 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -11308,3 +11308,72 @@ TEST(GCInFailedAccessCheckCallback) { // the other tests. v8::V8::SetFailedAccessCheckCallbackFunction(NULL); } + + +TEST(StringCheckMultipleContexts) { + const char* code = + "(function() { return \"a\".charAt(0); })()"; + + { + // Run the code twice in the first context to initialize the call IC. + v8::HandleScope scope; + LocalContext context1; + ExpectString(code, "a"); + ExpectString(code, "a"); + } + + { + // Change the String.prototype in the second context and check + // that the right function gets called. + v8::HandleScope scope; + LocalContext context2; + CompileRun("String.prototype.charAt = function() { return \"not a\"; }"); + ExpectString(code, "not a"); + } +} + + +TEST(NumberCheckMultipleContexts) { + const char* code = + "(function() { return (42).toString(); })()"; + + { + // Run the code twice in the first context to initialize the call IC. + v8::HandleScope scope; + LocalContext context1; + ExpectString(code, "42"); + ExpectString(code, "42"); + } + + { + // Change the Number.prototype in the second context and check + // that the right function gets called. + v8::HandleScope scope; + LocalContext context2; + CompileRun("Number.prototype.toString = function() { return \"not 42\"; }"); + ExpectString(code, "not 42"); + } +} + + +TEST(BooleanCheckMultipleContexts) { + const char* code = + "(function() { return true.toString(); })()"; + + { + // Run the code twice in the first context to initialize the call IC. + v8::HandleScope scope; + LocalContext context1; + ExpectString(code, "true"); + ExpectString(code, "true"); + } + + { + // Change the Boolean.prototype in the second context and check + // that the right function gets called. + v8::HandleScope scope; + LocalContext context2; + CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); + ExpectString(code, ""); + } +} -- 2.7.4