Reviewers: rossberg,
Description:
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.
[email protected]
BUG=v8:2268
TEST=cctest/test-api
Please review this at https://codereview.chromium.org/11308197/
SVN Base: https://v8.googlecode.com/svn/branches/bleeding_edge
Affected files:
M src/builtins.cc
M src/stub-cache.cc
M test/cctest/test-api.cc
Index: src/builtins.cc
diff --git a/src/builtins.cc b/src/builtins.cc
index
5c8e32b4269d554d9d4452e05e55d439c9951602..5474f2b580899b44617cd6be1a2bdaf06dff221c
100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -1263,12 +1263,30 @@ 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) {
+ for (; object != heap->null_value(); object = object->GetPrototype()) {
+ if (object->IsInstanceOf(type)) return object;
+ Object* proto = object->GetPrototype();
+ if (!proto->IsJSObject() ||
+ !JSObject::cast(proto)->map()->is_hidden_prototype()) {
+ break;
+ }
+ }
+ 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,
@@ -1281,15 +1299,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
@@ -1302,13 +1315,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;
}
Index: src/stub-cache.cc
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index
1f708b3ca63c94f6d7bf49e9c10d66e23f1de8ca..bfed6bbac7f5db4fa5f372b1c3d7554886c1b2ae
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>(JSObject::cast(object->GetPrototype()));
+ if (!object->map()->is_hidden_prototype()) return kInvalidProtoDepth;
++depth;
}
if (holder->IsInstanceOf(*expected_receiver_type_)) return depth;
Index: test/cctest/test-api.cc
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index
a51d3012a5a8f3c1929d122f9288bb95d2236e2c..0f33dedfcfa51bcc11f64a029cb1305e8a080967
100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -8063,12 +8063,8 @@ THREADED_TEST(ShadowObject) {
Local<ObjectTemplate> proto = t->PrototypeTemplate();
Local<ObjectTemplate> instance = t->InstanceTemplate();
- // Only allow calls of f on instances of t.
- Local<v8::Signature> signature = v8::Signature::New(t);
proto->Set(v8_str("f"),
- v8::FunctionTemplate::New(ShadowFunctionCallback,
- Local<Value>(),
- signature));
+ v8::FunctionTemplate::New(ShadowFunctionCallback,
Local<Value>()));
proto->Set(v8_str("x"), v8_num(12));
instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter);
@@ -9933,6 +9929,7 @@
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) {
v8::Signature::New(fun_templ));
v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
NULL, NULL, NULL, NULL,
@@ -9963,6 +9960,7 @@
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) {
v8::Signature::New(fun_templ));
v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
NULL, NULL, NULL, NULL,
@@ -9999,6 +9997,7 @@
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) {
v8::Signature::New(fun_templ));
v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
NULL, NULL, NULL, NULL,
@@ -10035,6 +10034,7 @@
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) {
v8::Signature::New(fun_templ));
v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
NULL, NULL, NULL, NULL,
@@ -10074,6 +10074,7 @@
THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) {
v8::Signature::New(fun_templ));
v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
templ->SetNamedPropertyHandler(InterceptorCallICFastApi,
NULL, NULL, NULL, NULL,
@@ -10136,6 +10137,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature) {
v8::Signature::New(fun_templ));
v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
CHECK(!templ.IsEmpty());
LocalContext context;
@@ -10163,6 +10165,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) {
v8::Signature::New(fun_templ));
v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
CHECK(!templ.IsEmpty());
LocalContext context;
@@ -10195,6 +10198,7 @@ THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) {
v8::Signature::New(fun_templ));
v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
CHECK(!templ.IsEmpty());
LocalContext context;
@@ -10221,6 +10225,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<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New();
+ v8::Handle<v8::FunctionTemplate> method_templ =
+ v8::FunctionTemplate::New(FastApiCallback_SimpleSignature,
+ v8_str("method_data"),
+ v8::Signature::New(fun_templ));
+ v8::Handle<v8::ObjectTemplate> proto_templ =
fun_templ->PrototypeTemplate();
+ proto_templ->Set(v8_str("method"), method_templ);
+ fun_templ->SetHiddenPrototype(true);
+ v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate());
+ CHECK(!templ.IsEmpty());
+ LocalContext context;
+ v8::Handle<v8::Function> 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<Value> keyed_call_ic_function;
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev