From 5966276d5662b2b3f5b46d71905c014af12a4980 Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Tue, 4 Dec 2012 13:45:48 +0000 Subject: [PATCH] Change deprecated semantics of function template signatures. This changes how FunctionTemplate interprets a Signature that specifies compatible receivers and arguments. Only the hidden prototype chain will be considered when searching for compatible receivers. This prevents JavaScript from modifying the inheritance relationship set up by the embedder. R=rossberg@chromium.org BUG=v8:2268 TEST=cctest/test-api Review URL: https://codereview.chromium.org/11308197 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13131 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/builtins.cc | 41 +++++++++++++++++++++++----------------- src/stub-cache.cc | 1 + test/cctest/test-api.cc | 50 ++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 70 insertions(+), 22 deletions(-) diff --git a/src/builtins.cc b/src/builtins.cc index d9f8d15..d62713d 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -1252,12 +1252,28 @@ BUILTIN(StrictModePoisonPill) { // +// Searches the hidden prototype chain of the given object for the first +// object that is an instance of the given type. If no such object can +// be found then Heap::null_value() is returned. +static inline Object* FindHidden(Heap* heap, + Object* object, + FunctionTemplateInfo* type) { + if (object->IsInstanceOf(type)) return object; + Object* proto = object->GetPrototype(); + if (proto->IsJSObject() && + JSObject::cast(proto)->map()->is_hidden_prototype()) { + return FindHidden(heap, proto, type); + } + return heap->null_value(); +} + + // Returns the holder JSObject if the function can legally be called // with this receiver. Returns Heap::null_value() if the call is // illegal. Any arguments that don't fit the expected type is -// overwritten with undefined. Arguments that do fit the expected -// type is overwritten with the object in the prototype chain that -// actually has that type. +// overwritten with undefined. Note that holder and the arguments are +// implicitly rewritten with the first object in the hidden prototype +// chain that actually has the expected type. static inline Object* TypeCheck(Heap* heap, int argc, Object** argv, @@ -1270,15 +1286,10 @@ static inline Object* TypeCheck(Heap* heap, SignatureInfo* sig = SignatureInfo::cast(sig_obj); // If necessary, check the receiver Object* recv_type = sig->receiver(); - Object* holder = recv; if (!recv_type->IsUndefined()) { - for (; holder != heap->null_value(); holder = holder->GetPrototype()) { - if (holder->IsInstanceOf(FunctionTemplateInfo::cast(recv_type))) { - break; - } - } - if (holder == heap->null_value()) return holder; + holder = FindHidden(heap, holder, FunctionTemplateInfo::cast(recv_type)); + if (holder == heap->null_value()) return heap->null_value(); } Object* args_obj = sig->args(); // If there is no argument signature we're done @@ -1291,13 +1302,9 @@ static inline Object* TypeCheck(Heap* heap, if (argtype->IsUndefined()) continue; Object** arg = &argv[-1 - i]; Object* current = *arg; - for (; current != heap->null_value(); current = current->GetPrototype()) { - if (current->IsInstanceOf(FunctionTemplateInfo::cast(argtype))) { - *arg = current; - break; - } - } - if (current == heap->null_value()) *arg = heap->undefined_value(); + current = FindHidden(heap, current, FunctionTemplateInfo::cast(argtype)); + if (current == heap->null_value()) current = heap->undefined_value(); + *arg = current; } return holder; } diff --git a/src/stub-cache.cc b/src/stub-cache.cc index 1f708b3..bfed6bb 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -1562,6 +1562,7 @@ int CallOptimization::GetPrototypeDepthOfExpectedType( while (!object.is_identical_to(holder)) { if (object->IsInstanceOf(*expected_receiver_type_)) return depth; object = Handle(JSObject::cast(object->GetPrototype())); + if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth; ++depth; } if (holder->IsInstanceOf(*expected_receiver_type_)) return depth; diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index 1dbc399..1610dcd 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -8093,12 +8093,8 @@ THREADED_TEST(ShadowObject) { Local proto = t->PrototypeTemplate(); Local instance = t->InstanceTemplate(); - // Only allow calls of f on instances of t. - Local signature = v8::Signature::New(t); proto->Set(v8_str("f"), - v8::FunctionTemplate::New(ShadowFunctionCallback, - Local(), - signature)); + v8::FunctionTemplate::New(ShadowFunctionCallback, Local())); proto->Set(v8_str("x"), v8_num(12)); instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); @@ -9963,6 +9959,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) { v8::Signature::New(fun_templ)); v8::Handle proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -9993,6 +9990,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { v8::Signature::New(fun_templ)); v8::Handle proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -10029,6 +10027,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { v8::Signature::New(fun_templ)); v8::Handle proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -10065,6 +10064,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { v8::Signature::New(fun_templ)); v8::Handle proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -10104,6 +10104,7 @@ THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { v8::Signature::New(fun_templ)); v8::Handle proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle templ = fun_templ->InstanceTemplate(); templ->SetNamedPropertyHandler(InterceptorCallICFastApi, NULL, NULL, NULL, NULL, @@ -10166,6 +10167,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature) { v8::Signature::New(fun_templ)); v8::Handle proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -10193,6 +10195,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) { v8::Signature::New(fun_templ)); v8::Handle proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -10225,6 +10228,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) { v8::Signature::New(fun_templ)); v8::Handle proto_templ = fun_templ->PrototypeTemplate(); proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); v8::Handle templ(fun_templ->InstanceTemplate()); CHECK(!templ.IsEmpty()); LocalContext context; @@ -10251,6 +10255,42 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) { CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); } +THREADED_TEST(CallICFastApi_SimpleSignature_TypeError) { + v8::HandleScope scope; + v8::Handle fun_templ = v8::FunctionTemplate::New(); + v8::Handle method_templ = + v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, + v8_str("method_data"), + v8::Signature::New(fun_templ)); + v8::Handle proto_templ = fun_templ->PrototypeTemplate(); + proto_templ->Set(v8_str("method"), method_templ); + fun_templ->SetHiddenPrototype(true); + v8::Handle templ(fun_templ->InstanceTemplate()); + CHECK(!templ.IsEmpty()); + LocalContext context; + v8::Handle fun = fun_templ->GetFunction(); + GenerateSomeGarbage(); + context->Global()->Set(v8_str("o"), fun->NewInstance()); + v8::TryCatch try_catch; + CompileRun( + "o.foo = 17;" + "var receiver = {};" + "receiver.__proto__ = o;" + "var result = 0;" + "var saved_result = 0;" + "for (var i = 0; i < 100; i++) {" + " result = receiver.method(41);" + " if (i == 50) {" + " saved_result = result;" + " receiver = Object.create(receiver);" + " }" + "}"); + CHECK(try_catch.HasCaught()); + CHECK_EQ(v8_str("TypeError: Illegal invocation"), + try_catch.Exception()->ToString()); + CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); +} + v8::Handle keyed_call_ic_function; -- 2.7.4