Commit c6c55a69 authored by vitalyr@chromium.org's avatar vitalyr@chromium.org

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
parent 3b8235b3
...@@ -266,7 +266,12 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, ...@@ -266,7 +266,12 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( 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. // Get the global function with the given index.
JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
// Load its initial map. The global functions all have initial maps. // Load its initial map. The global functions all have initial maps.
...@@ -1434,7 +1439,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall( ...@@ -1434,7 +1439,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(), GenerateDirectLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX, Context::STRING_FUNCTION_INDEX,
r0); r0,
&miss);
ASSERT(object != holder); ASSERT(object != holder);
CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
r1, r3, r4, name, &miss); r1, r3, r4, name, &miss);
...@@ -1505,7 +1511,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1505,7 +1511,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(), GenerateDirectLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX, Context::STRING_FUNCTION_INDEX,
r0); r0,
&miss);
ASSERT(object != holder); ASSERT(object != holder);
CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder,
r1, r3, r4, name, &miss); r1, r3, r4, name, &miss);
...@@ -1705,7 +1712,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1705,7 +1712,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ b(hs, &miss); __ b(hs, &miss);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::STRING_FUNCTION_INDEX, r0); masm(), Context::STRING_FUNCTION_INDEX, r0, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
r1, r4, name, &miss); r1, r4, name, &miss);
} }
...@@ -1725,7 +1732,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1725,7 +1732,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ bind(&fast); __ bind(&fast);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::NUMBER_FUNCTION_INDEX, r0); masm(), Context::NUMBER_FUNCTION_INDEX, r0, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
r1, r4, name, &miss); r1, r4, name, &miss);
} }
...@@ -1748,7 +1755,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1748,7 +1755,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ bind(&fast); __ bind(&fast);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::BOOLEAN_FUNCTION_INDEX, r0); masm(), Context::BOOLEAN_FUNCTION_INDEX, r0, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3, CheckPrototypes(JSObject::cast(object->GetPrototype()), r0, holder, r3,
r1, r4, name, &miss); r1, r4, name, &miss);
} }
......
...@@ -265,7 +265,11 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, ...@@ -265,7 +265,11 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( 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. // Get the global function with the given index.
JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
// Load its initial map. The global functions all have initial maps. // Load its initial map. The global functions all have initial maps.
...@@ -1626,7 +1630,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall( ...@@ -1626,7 +1630,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(), GenerateDirectLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX, Context::STRING_FUNCTION_INDEX,
eax); eax,
&miss);
ASSERT(object != holder); ASSERT(object != holder);
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
ebx, edx, edi, name, &miss); ebx, edx, edi, name, &miss);
...@@ -1695,7 +1700,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1695,7 +1700,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(), GenerateDirectLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX, Context::STRING_FUNCTION_INDEX,
eax); eax,
&miss);
ASSERT(object != holder); ASSERT(object != holder);
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
ebx, edx, edi, name, &miss); ebx, edx, edi, name, &miss);
...@@ -1894,7 +1900,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1894,7 +1900,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ j(above_equal, &miss, not_taken); __ j(above_equal, &miss, not_taken);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::STRING_FUNCTION_INDEX, eax); masm(), Context::STRING_FUNCTION_INDEX, eax, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
ebx, edx, edi, name, &miss); ebx, edx, edi, name, &miss);
} }
...@@ -1914,7 +1920,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1914,7 +1920,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ bind(&fast); __ bind(&fast);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::NUMBER_FUNCTION_INDEX, eax); masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
ebx, edx, edi, name, &miss); ebx, edx, edi, name, &miss);
} }
...@@ -1935,7 +1941,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1935,7 +1941,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ bind(&fast); __ bind(&fast);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::BOOLEAN_FUNCTION_INDEX, eax); masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder,
ebx, edx, edi, name, &miss); ebx, edx, edi, name, &miss);
} }
......
...@@ -370,13 +370,15 @@ class StubCompiler BASE_EMBEDDED { ...@@ -370,13 +370,15 @@ class StubCompiler BASE_EMBEDDED {
Register prototype); Register prototype);
// Generates prototype loading code that uses the objects from the // Generates prototype loading code that uses the objects from the
// context we were in when this function was called. This ties the // context we were in when this function was called. If the context
// generated code to a particular context and so must not be used in // has changed, a jump to miss is performed. This ties the generated
// cases where the generated code is not allowed to have references // code to a particular context and so must not be used in cases
// to objects from a context. // where the generated code is not allowed to have references to
// objects from a context.
static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm, static void GenerateDirectLoadGlobalFunctionPrototype(MacroAssembler* masm,
int index, int index,
Register prototype); Register prototype,
Label* miss);
static void GenerateFastPropertyLoad(MacroAssembler* masm, static void GenerateFastPropertyLoad(MacroAssembler* masm,
Register dst, Register src, Register dst, Register src,
......
...@@ -216,7 +216,12 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, ...@@ -216,7 +216,12 @@ void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm,
void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( 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. // Get the global function with the given index.
JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); JSFunction* function = JSFunction::cast(Top::global_context()->get(index));
// Load its initial map. The global functions all have initial maps. // Load its initial map. The global functions all have initial maps.
...@@ -964,7 +969,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -964,7 +969,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ j(above_equal, &miss); __ j(above_equal, &miss);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::STRING_FUNCTION_INDEX, rax); masm(), Context::STRING_FUNCTION_INDEX, rax, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
rbx, rdx, rdi, name, &miss); rbx, rdx, rdi, name, &miss);
} }
...@@ -983,7 +988,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -983,7 +988,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ bind(&fast); __ bind(&fast);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::NUMBER_FUNCTION_INDEX, rax); masm(), Context::NUMBER_FUNCTION_INDEX, rax, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
rbx, rdx, rdi, name, &miss); rbx, rdx, rdi, name, &miss);
} }
...@@ -1004,7 +1009,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object, ...@@ -1004,7 +1009,7 @@ Object* CallStubCompiler::CompileCallConstant(Object* object,
__ bind(&fast); __ bind(&fast);
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype( GenerateDirectLoadGlobalFunctionPrototype(
masm(), Context::BOOLEAN_FUNCTION_INDEX, rax); masm(), Context::BOOLEAN_FUNCTION_INDEX, rax, &miss);
CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
rbx, rdx, rdi, name, &miss); rbx, rdx, rdi, name, &miss);
} }
...@@ -1358,7 +1363,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object, ...@@ -1358,7 +1363,8 @@ Object* CallStubCompiler::CompileStringCharAtCall(Object* object,
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(), GenerateDirectLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX, Context::STRING_FUNCTION_INDEX,
rax); rax,
&miss);
ASSERT(object != holder); ASSERT(object != holder);
CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
rbx, rdx, rdi, name, &miss); rbx, rdx, rdi, name, &miss);
...@@ -1429,7 +1435,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall( ...@@ -1429,7 +1435,8 @@ Object* CallStubCompiler::CompileStringCharCodeAtCall(
// Check that the maps starting from the prototype haven't changed. // Check that the maps starting from the prototype haven't changed.
GenerateDirectLoadGlobalFunctionPrototype(masm(), GenerateDirectLoadGlobalFunctionPrototype(masm(),
Context::STRING_FUNCTION_INDEX, Context::STRING_FUNCTION_INDEX,
rax); rax,
&miss);
ASSERT(object != holder); ASSERT(object != holder);
CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder, CheckPrototypes(JSObject::cast(object->GetPrototype()), rax, holder,
rbx, rdx, rdi, name, &miss); rbx, rdx, rdi, name, &miss);
......
...@@ -11308,3 +11308,72 @@ TEST(GCInFailedAccessCheckCallback) { ...@@ -11308,3 +11308,72 @@ TEST(GCInFailedAccessCheckCallback) {
// the other tests. // the other tests.
v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 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, "");
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment