Function::Call and Object::CallAsFunction APIs should allow v8::Value as a receiver

Since the primitive values can be a receiver of strict mode functions in
ECMA262 5.1th, v8::Function::Call and Object::CallAsFunction should take
v8::Value as a receiver instead of v8::Object.

BUG=v8:2915
TEST=cctest/test-api
R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/24920003

Patch from Yusuke Suzuki <yusukesuzuki@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17003 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mstarzinger@chromium.org 2013-09-30 11:47:36 +00:00
parent f5e783de49
commit f03dbcff94
3 changed files with 124 additions and 7 deletions

View File

@ -2322,7 +2322,7 @@ class V8_EXPORT Object : public Value {
* Call an Object as a function if a callback is set by the
* ObjectTemplate::SetCallAsFunctionHandler method.
*/
Local<Value> CallAsFunction(Handle<Object> recv,
Local<Value> CallAsFunction(Handle<Value> recv,
int argc,
Handle<Value> argv[]);
@ -2495,7 +2495,7 @@ class V8_EXPORT Function : public Object {
Local<Object> NewInstance() const;
Local<Object> NewInstance(int argc, Handle<Value> argv[]) const;
Local<Value> Call(Handle<Object> recv, int argc, Handle<Value> argv[]);
Local<Value> Call(Handle<Value> recv, int argc, Handle<Value> argv[]);
void SetName(Handle<String> name);
Handle<Value> GetName() const;

View File

@ -3936,7 +3936,7 @@ bool v8::Object::IsCallable() {
}
Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv,
Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Value> recv,
int argc,
v8::Handle<v8::Value> argv[]) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
@ -3964,7 +3964,7 @@ Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv,
}
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> returned = i::Execution::Call(
isolate, fun, recv_obj, argc, args, &has_pending_exception);
isolate, fun, recv_obj, argc, args, &has_pending_exception, true);
EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Value>());
return Utils::ToLocal(scope.CloseAndEscape(returned));
}
@ -4048,7 +4048,7 @@ Local<v8::Object> Function::NewInstance(int argc,
}
Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc,
Local<v8::Value> Function::Call(v8::Handle<v8::Value> recv, int argc,
v8::Handle<v8::Value> argv[]) {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
ON_BAILOUT(isolate, "v8::Function::Call()", return Local<v8::Value>());
@ -4065,7 +4065,7 @@ Local<v8::Value> Function::Call(v8::Handle<v8::Object> recv, int argc,
i::Handle<i::Object>* args = reinterpret_cast<i::Handle<i::Object>*>(argv);
EXCEPTION_PREAMBLE(isolate);
i::Handle<i::Object> returned = i::Execution::Call(
isolate, fun, recv_obj, argc, args, &has_pending_exception);
isolate, fun, recv_obj, argc, args, &has_pending_exception, true);
EXCEPTION_BAILOUT_CHECK_DO_CALLBACK(isolate, Local<Object>());
raw_result = *returned;
}

View File

@ -4011,7 +4011,8 @@ THREADED_TEST(Vector) {
THREADED_TEST(FunctionCall) {
LocalContext context;
v8::HandleScope scope(context->GetIsolate());
v8::Isolate* isolate = context->GetIsolate();
v8::HandleScope scope(isolate);
CompileRun(
"function Foo() {"
" var result = [];"
@ -4019,9 +4020,20 @@ THREADED_TEST(FunctionCall) {
" result.push(arguments[i]);"
" }"
" return result;"
"}"
"function ReturnThisSloppy() {"
" return this;"
"}"
"function ReturnThisStrict() {"
" 'use strict';"
" return this;"
"}");
Local<Function> Foo =
Local<Function>::Cast(context->Global()->Get(v8_str("Foo")));
Local<Function> ReturnThisSloppy =
Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisSloppy")));
Local<Function> ReturnThisStrict =
Local<Function>::Cast(context->Global()->Get(v8_str("ReturnThisStrict")));
v8::Handle<Value>* args0 = NULL;
Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0));
@ -4058,6 +4070,31 @@ THREADED_TEST(FunctionCall) {
CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue());
CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue());
CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue());
Local<v8::Value> r1 = ReturnThisSloppy->Call(v8::Undefined(isolate), 0, NULL);
CHECK(r1->StrictEquals(context->Global()));
Local<v8::Value> r2 = ReturnThisSloppy->Call(v8::Null(isolate), 0, NULL);
CHECK(r2->StrictEquals(context->Global()));
Local<v8::Value> r3 = ReturnThisSloppy->Call(v8_num(42), 0, NULL);
CHECK(r3->IsNumberObject());
CHECK_EQ(42.0, r3.As<v8::NumberObject>()->ValueOf());
Local<v8::Value> r4 = ReturnThisSloppy->Call(v8_str("hello"), 0, NULL);
CHECK(r4->IsStringObject());
CHECK(r4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
Local<v8::Value> r5 = ReturnThisSloppy->Call(v8::True(isolate), 0, NULL);
CHECK(r5->IsBooleanObject());
CHECK(r5.As<v8::BooleanObject>()->ValueOf());
Local<v8::Value> r6 = ReturnThisStrict->Call(v8::Undefined(isolate), 0, NULL);
CHECK(r6->IsUndefined());
Local<v8::Value> r7 = ReturnThisStrict->Call(v8::Null(isolate), 0, NULL);
CHECK(r7->IsNull());
Local<v8::Value> r8 = ReturnThisStrict->Call(v8_num(42), 0, NULL);
CHECK(r8->StrictEquals(v8_num(42)));
Local<v8::Value> r9 = ReturnThisStrict->Call(v8_str("hello"), 0, NULL);
CHECK(r9->StrictEquals(v8_str("hello")));
Local<v8::Value> r10 = ReturnThisStrict->Call(v8::True(isolate), 0, NULL);
CHECK(r10->StrictEquals(v8::True(isolate)));
}
@ -10177,6 +10214,11 @@ static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) {
}
static void ReturnThis(const v8::FunctionCallbackInfo<v8::Value>& args) {
args.GetReturnValue().Set(args.This());
}
// Test that a call handler can be set for objects which will allow
// non-function objects created through the API to be called as
// functions.
@ -10289,6 +10331,81 @@ THREADED_TEST(CallAsFunction) {
CHECK_EQ("23", *exception_value2);
try_catch.Reset();
}
{ v8::Isolate* isolate = context->GetIsolate();
Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
Local<ObjectTemplate> instance_template = t->InstanceTemplate();
instance_template->SetCallAsFunctionHandler(ReturnThis);
Local<v8::Object> instance = t->GetFunction()->NewInstance();
Local<v8::Value> a1 =
instance->CallAsFunction(v8::Undefined(isolate), 0, NULL);
CHECK(a1->StrictEquals(instance));
Local<v8::Value> a2 =
instance->CallAsFunction(v8::Null(isolate), 0, NULL);
CHECK(a2->StrictEquals(instance));
Local<v8::Value> a3 =
instance->CallAsFunction(v8_num(42), 0, NULL);
CHECK(a3->StrictEquals(instance));
Local<v8::Value> a4 =
instance->CallAsFunction(v8_str("hello"), 0, NULL);
CHECK(a4->StrictEquals(instance));
Local<v8::Value> a5 =
instance->CallAsFunction(v8::True(isolate), 0, NULL);
CHECK(a5->StrictEquals(instance));
}
{ v8::Isolate* isolate = context->GetIsolate();
CompileRun(
"function ReturnThisSloppy() {"
" return this;"
"}"
"function ReturnThisStrict() {"
" 'use strict';"
" return this;"
"}");
Local<Function> ReturnThisSloppy =
Local<Function>::Cast(
context->Global()->Get(v8_str("ReturnThisSloppy")));
Local<Function> ReturnThisStrict =
Local<Function>::Cast(
context->Global()->Get(v8_str("ReturnThisStrict")));
Local<v8::Value> a1 =
ReturnThisSloppy->CallAsFunction(v8::Undefined(isolate), 0, NULL);
CHECK(a1->StrictEquals(context->Global()));
Local<v8::Value> a2 =
ReturnThisSloppy->CallAsFunction(v8::Null(isolate), 0, NULL);
CHECK(a2->StrictEquals(context->Global()));
Local<v8::Value> a3 =
ReturnThisSloppy->CallAsFunction(v8_num(42), 0, NULL);
CHECK(a3->IsNumberObject());
CHECK_EQ(42.0, a3.As<v8::NumberObject>()->ValueOf());
Local<v8::Value> a4 =
ReturnThisSloppy->CallAsFunction(v8_str("hello"), 0, NULL);
CHECK(a4->IsStringObject());
CHECK(a4.As<v8::StringObject>()->ValueOf()->StrictEquals(v8_str("hello")));
Local<v8::Value> a5 =
ReturnThisSloppy->CallAsFunction(v8::True(isolate), 0, NULL);
CHECK(a5->IsBooleanObject());
CHECK(a5.As<v8::BooleanObject>()->ValueOf());
Local<v8::Value> a6 =
ReturnThisStrict->CallAsFunction(v8::Undefined(isolate), 0, NULL);
CHECK(a6->IsUndefined());
Local<v8::Value> a7 =
ReturnThisStrict->CallAsFunction(v8::Null(isolate), 0, NULL);
CHECK(a7->IsNull());
Local<v8::Value> a8 =
ReturnThisStrict->CallAsFunction(v8_num(42), 0, NULL);
CHECK(a8->StrictEquals(v8_num(42)));
Local<v8::Value> a9 =
ReturnThisStrict->CallAsFunction(v8_str("hello"), 0, NULL);
CHECK(a9->StrictEquals(v8_str("hello")));
Local<v8::Value> a10 =
ReturnThisStrict->CallAsFunction(v8::True(isolate), 0, NULL);
CHECK(a10->StrictEquals(v8::True(isolate)));
}
}