Revision: 7773
Author: [email protected]
Date: Wed May 4 03:03:49 2011
Log: Add Call method to the Object class in the API
Patch by Peter Varga.
BUG=v8:1336
TEST=cctest/test-api/CallAsFunction
Review URL: http://codereview.chromium.org/6883045
http://code.google.com/p/v8/source/detail?r=7773
Modified:
/branches/bleeding_edge/include/v8.h
/branches/bleeding_edge/src/api.cc
/branches/bleeding_edge/src/execution.cc
/branches/bleeding_edge/src/execution.h
/branches/bleeding_edge/test/cctest/test-api.cc
=======================================
--- /branches/bleeding_edge/include/v8.h Wed May 4 00:28:27 2011
+++ /branches/bleeding_edge/include/v8.h Wed May 4 03:03:49 2011
@@ -1606,6 +1606,14 @@
V8EXPORT ExternalArrayType GetIndexedPropertiesExternalArrayDataType();
V8EXPORT int GetIndexedPropertiesExternalArrayDataLength();
+ /**
+ * Call an Object as a function if a callback is set by the
+ * ObjectTemplate::SetCallAsFunctionHandler method.
+ */
+ V8EXPORT Local<Value> CallAsFunction(Handle<Object> recv,
+ int argc,
+ Handle<Value> argv[]);
+
V8EXPORT static Local<Object> New();
static inline Object* Cast(Value* obj);
private:
=======================================
--- /branches/bleeding_edge/src/api.cc Mon May 2 22:40:47 2011
+++ /branches/bleeding_edge/src/api.cc Wed May 4 03:03:49 2011
@@ -3253,6 +3253,37 @@
return -1;
}
}
+
+
+Local<v8::Value> Object::CallAsFunction(v8::Handle<v8::Object> recv, int
argc,
+ v8::Handle<v8::Value> argv[]) {
+ i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
+ ON_BAILOUT(isolate, "v8::Object::CallAsFunction()",
+ return Local<v8::Value>());
+ LOG_API(isolate, "Object::CallAsFunction");
+ ENTER_V8(isolate);
+ HandleScope scope;
+ i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
+ i::Handle<i::Object> recv_obj = Utils::OpenHandle(*recv);
+ STATIC_ASSERT(sizeof(v8::Handle<v8::Value>) == sizeof(i::Object**));
+ i::Object*** args = reinterpret_cast<i::Object***>(argv);
+ i::Handle<i::JSFunction> fun = i::Handle<i::JSFunction>();
+ if (obj->IsJSFunction()) {
+ fun = i::Handle<i::JSFunction>::cast(obj);
+ } else {
+ EXCEPTION_PREAMBLE(isolate);
+ i::Handle<i::Object> delegate =
+ i::Execution::TryGetFunctionDelegate(obj, &has_pending_exception);
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+ fun = i::Handle<i::JSFunction>::cast(delegate);
+ recv_obj = obj;
+ }
+ EXCEPTION_PREAMBLE(isolate);
+ i::Handle<i::Object> returned =
+ i::Execution::Call(fun, recv_obj, argc, args,
&has_pending_exception);
+ EXCEPTION_BAILOUT_CHECK(isolate, Local<Value>());
+ return
scope.Close(Utils::ToLocal(i::Handle<i::JSObject>::cast(returned)));
+}
Local<v8::Object> Function::NewInstance() const {
=======================================
--- /branches/bleeding_edge/src/execution.cc Fri Apr 29 15:16:45 2011
+++ /branches/bleeding_edge/src/execution.cc Wed May 4 03:03:49 2011
@@ -232,6 +232,30 @@
return factory->undefined_value();
}
+
+
+Handle<Object> Execution::TryGetFunctionDelegate(Handle<Object> object,
+ bool*
has_pending_exception) {
+ ASSERT(!object->IsJSFunction());
+ Isolate* isolate = Isolate::Current();
+
+ // Objects created through the API can have an instance-call handler
+ // that should be used when calling the object as a function.
+ if (object->IsHeapObject() &&
+ HeapObject::cast(*object)->map()->has_instance_call_handler()) {
+ return Handle<JSFunction>(
+ isolate->global_context()->call_as_function_delegate());
+ }
+
+ // If the Object doesn't have an instance-call handler we should
+ // throw a non-callable exception.
+ i::Handle<i::Object> error_obj = isolate->factory()->NewTypeError(
+ "called_non_callable", i::HandleVector<i::Object>(&object, 1));
+ isolate->Throw(*error_obj);
+ *has_pending_exception = true;
+
+ return isolate->factory()->undefined_value();
+}
Handle<Object> Execution::GetConstructorDelegate(Handle<Object> object) {
=======================================
--- /branches/bleeding_edge/src/execution.h Fri Mar 18 13:35:07 2011
+++ /branches/bleeding_edge/src/execution.h Wed May 4 03:03:49 2011
@@ -138,6 +138,8 @@
// Get a function delegate (or undefined) for the given non-function
// object. Used for support calling objects as functions.
static Handle<Object> GetFunctionDelegate(Handle<Object> object);
+ static Handle<Object> TryGetFunctionDelegate(Handle<Object> object,
+ bool*
has_pending_exception);
// Get a function delegate (or undefined) for the given non-function
// object. Used for support calling objects as constructors.
=======================================
--- /branches/bleeding_edge/test/cctest/test-api.cc Wed May 4 00:28:27 2011
+++ /branches/bleeding_edge/test/cctest/test-api.cc Wed May 4 03:03:49 2011
@@ -6962,50 +6962,111 @@
v8::HandleScope scope;
LocalContext context;
- Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
- Local<ObjectTemplate> instance_template = t->InstanceTemplate();
- instance_template->SetCallAsFunctionHandler(call_as_function);
- Local<v8::Object> instance = t->GetFunction()->NewInstance();
- context->Global()->Set(v8_str("obj"), instance);
- v8::TryCatch try_catch;
- Local<Value> value;
- CHECK(!try_catch.HasCaught());
-
- value = CompileRun("obj(42)");
- CHECK(!try_catch.HasCaught());
- CHECK_EQ(42, value->Int32Value());
-
- value = CompileRun("(function(o){return o(49)})(obj)");
- CHECK(!try_catch.HasCaught());
- CHECK_EQ(49, value->Int32Value());
-
- // test special case of call as function
- value = CompileRun("[obj]['0'](45)");
- CHECK(!try_catch.HasCaught());
- CHECK_EQ(45, value->Int32Value());
-
- value = CompileRun("obj.call = Function.prototype.call;"
- "obj.call(null, 87)");
- CHECK(!try_catch.HasCaught());
- CHECK_EQ(87, value->Int32Value());
-
- // Regression tests for bug #1116356: Calling call through call/apply
- // must work for non-function receivers.
- const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])";
- value = CompileRun(apply_99);
- CHECK(!try_catch.HasCaught());
- CHECK_EQ(99, value->Int32Value());
-
- const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
- value = CompileRun(call_17);
- CHECK(!try_catch.HasCaught());
- CHECK_EQ(17, value->Int32Value());
-
- // Check that the call-as-function handler can be called through
- // new.
- value = CompileRun("new obj(43)");
- CHECK(!try_catch.HasCaught());
- CHECK_EQ(-43, value->Int32Value());
+ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+ instance_template->SetCallAsFunctionHandler(call_as_function);
+ Local<v8::Object> instance = t->GetFunction()->NewInstance();
+ context->Global()->Set(v8_str("obj"), instance);
+ v8::TryCatch try_catch;
+ Local<Value> value;
+ CHECK(!try_catch.HasCaught());
+
+ value = CompileRun("obj(42)");
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(42, value->Int32Value());
+
+ value = CompileRun("(function(o){return o(49)})(obj)");
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(49, value->Int32Value());
+
+ // test special case of call as function
+ value = CompileRun("[obj]['0'](45)");
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(45, value->Int32Value());
+
+ value = CompileRun("obj.call = Function.prototype.call;"
+ "obj.call(null, 87)");
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(87, value->Int32Value());
+
+ // Regression tests for bug #1116356: Calling call through call/apply
+ // must work for non-function receivers.
+ const char* apply_99 = "Function.prototype.call.apply(obj, [this,
99])";
+ value = CompileRun(apply_99);
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(99, value->Int32Value());
+
+ const char* call_17 = "Function.prototype.call.call(obj, this, 17)";
+ value = CompileRun(call_17);
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(17, value->Int32Value());
+
+ // Check that the call-as-function handler can be called through
+ // new.
+ value = CompileRun("new obj(43)");
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(-43, value->Int32Value());
+
+ // Check that the call-as-function handler can be called through
+ // the API.
+ v8::Handle<Value> args[] = { v8_num(28) };
+ value = instance->CallAsFunction(instance, 1, args);
+ CHECK(!try_catch.HasCaught());
+ CHECK_EQ(28, value->Int32Value());
+ }
+
+ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+ Local<v8::Object> instance = t->GetFunction()->NewInstance();
+ context->Global()->Set(v8_str("obj2"), instance);
+ v8::TryCatch try_catch;
+ Local<Value> value;
+ CHECK(!try_catch.HasCaught());
+
+ // Call an object without call-as-function handler through the JS
+ value = CompileRun("obj2(28)");
+ CHECK(value.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value1(try_catch.Exception());
+ CHECK_EQ(*exception_value1,
+ "TypeError: Property 'obj2' of object "
+ "#<Object> is not a function");
+ try_catch.Reset();
+
+ // Call an object without call-as-function handler through the API
+ value = CompileRun("obj2(28)");
+ v8::Handle<Value> args[] = { v8_num(28) };
+ value = instance->CallAsFunction(instance, 1, args);
+ CHECK(value.IsEmpty());
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value2(try_catch.Exception());
+ CHECK_EQ(*exception_value2, "TypeError: [object Object] is not a
function");
+ try_catch.Reset();
+ }
+
+ { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New();
+ Local<ObjectTemplate> instance_template = t->InstanceTemplate();
+ instance_template->SetCallAsFunctionHandler(ThrowValue);
+ Local<v8::Object> instance = t->GetFunction()->NewInstance();
+ context->Global()->Set(v8_str("obj3"), instance);
+ v8::TryCatch try_catch;
+ Local<Value> value;
+ CHECK(!try_catch.HasCaught());
+
+ // Catch the exception which is thrown by call-as-function handler
+ value = CompileRun("obj3(22)");
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value1(try_catch.Exception());
+ CHECK_EQ(*exception_value1, "22");
+ try_catch.Reset();
+
+ v8::Handle<Value> args[] = { v8_num(23) };
+ value = instance->CallAsFunction(instance, 1, args);
+ CHECK(try_catch.HasCaught());
+ String::AsciiValue exception_value2(try_catch.Exception());
+ CHECK_EQ(*exception_value2, "23");
+ try_catch.Reset();
+ }
}
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev