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:
parent
f5e783de49
commit
f03dbcff94
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user