Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(875)

Unified Diff: src/builtins.cc

Issue 536065: Optimized calling of C++ builtins (and HandleApiCall (Closed)
Patch Set: Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/builtins.h ('k') | src/factory.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/builtins.cc
diff --git a/src/builtins.cc b/src/builtins.cc
index aa680d76b42b3f9acfa5712b7e4d142001dd76d2..f86e27a0c2cbc5dd536530134fe1235f1a2263de 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -36,8 +36,75 @@
namespace v8 {
namespace internal {
+namespace {
+
+// Arguments object passed to C++ builtins.
+template <BuiltinExtraArguments extra_args>
+class BuiltinArguments : public Arguments {
+ public:
+ Object*& operator[] (int index) {
+ ASSERT(index < length());
+ return Arguments::operator[](index);
+ }
+
+ template <class S> Handle<S> at(int index) {
+ ASSERT(index < length());
+ return Arguments::at<S>(index);
+ }
+
+ Handle<Object> receiver() {
+ return Arguments::at<Object>(0);
+ }
+
+ Handle<JSFunction> called_function() {
+ STATIC_ASSERT(extra_args == NEEDS_CALLED_FUNCTION);
+ return Arguments::at<JSFunction>(Arguments::length() - 1);
+ }
+
+ // Gets the total number of arguments including the receiver (but
+ // excluding extra arguments).
+ int length() const {
+ STATIC_ASSERT(extra_args == NO_EXTRA_ARGUMENTS);
+ return Arguments::length();
+ }
+
+#ifdef DEBUG
+ void Verify() {
+ // Check we have at least the receiver.
+ ASSERT(Arguments::length() >= 1);
+ }
+#endif
+};
+
+
+// Specialize BuiltinArguments for the called function extra argument.
+
+template <>
+int BuiltinArguments<NEEDS_CALLED_FUNCTION>::length() const {
+ return Arguments::length() - 1;
+}
+
+#ifdef DEBUG
+template <>
+void BuiltinArguments<NEEDS_CALLED_FUNCTION>::Verify() {
+ // Check we have at least the receiver and the called function.
+ ASSERT(Arguments::length() >= 2);
+ // Make sure cast to JSFunction succeeds.
+ called_function();
+}
+#endif
+
+
+#define DEF_ARG_TYPE(name, spec) \
+ typedef BuiltinArguments<spec> name##ArgumentsType;
+BUILTIN_LIST_C(DEF_ARG_TYPE)
+#undef DEF_ARG_TYPE
+
+} // namespace
+
+
// ----------------------------------------------------------------------------
-// Support macros for defining builtins in C.
+// Support macro for defining builtins in C++.
// ----------------------------------------------------------------------------
//
// A builtin function is defined by writing:
@@ -45,30 +112,26 @@ namespace internal {
// BUILTIN(name) {
// ...
// }
-// BUILTIN_END
//
-// In the body of the builtin function, the variable 'receiver' is visible.
-// The arguments can be accessed through the Arguments object args.
-//
-// args[0]: Receiver (also available as 'receiver')
-// args[1]: First argument
-// ...
-// args[n]: Last argument
-// args.length(): Number of arguments including the receiver.
-// ----------------------------------------------------------------------------
+// In the body of the builtin function the arguments can be accessed
+// through the BuiltinArguments object args.
+#ifdef DEBUG
-// TODO(428): We should consider passing whether or not the
-// builtin was invoked as a constructor as part of the
-// arguments. Maybe we also want to pass the called function?
-#define BUILTIN(name) \
- static Object* Builtin_##name(Arguments args) { \
- Handle<Object> receiver = args.at<Object>(0);
+#define BUILTIN(name) \
+ static Object* Builtin_Impl_##name(name##ArgumentsType args); \
+ static Object* Builtin_##name(name##ArgumentsType args) { \
+ args.Verify(); \
+ return Builtin_Impl_##name(args); \
+ } \
+ static Object* Builtin_Impl_##name(name##ArgumentsType args)
+#else // For release mode.
-#define BUILTIN_END \
- return Heap::undefined_value(); \
-}
+#define BUILTIN(name) \
+ static Object* Builtin_##name(name##ArgumentsType args)
+
+#endif
static inline bool CalledAsConstructor() {
@@ -126,13 +189,13 @@ Handle<Code> Builtins::GetCode(JavaScript id, bool* resolved) {
BUILTIN(Illegal) {
UNREACHABLE();
+ return Heap::undefined_value(); // Make compiler happy.
}
-BUILTIN_END
BUILTIN(EmptyFunction) {
+ return Heap::undefined_value();
}
-BUILTIN_END
BUILTIN(ArrayCodeGeneric) {
@@ -140,7 +203,7 @@ BUILTIN(ArrayCodeGeneric) {
JSArray* array;
if (CalledAsConstructor()) {
- array = JSArray::cast(*receiver);
+ array = JSArray::cast(*args.receiver());
} else {
// Allocate the JS Array
JSFunction* constructor =
@@ -194,11 +257,10 @@ BUILTIN(ArrayCodeGeneric) {
return array;
}
-BUILTIN_END
BUILTIN(ArrayPush) {
- JSArray* array = JSArray::cast(*receiver);
+ JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
// Make sure we have space for the elements.
@@ -233,11 +295,10 @@ BUILTIN(ArrayPush) {
array->set_length(Smi::FromInt(new_length), SKIP_WRITE_BARRIER);
return array->length();
}
-BUILTIN_END
BUILTIN(ArrayPop) {
- JSArray* array = JSArray::cast(*receiver);
+ JSArray* array = JSArray::cast(*args.receiver());
ASSERT(array->HasFastElements());
Object* undefined = Heap::undefined_value();
@@ -265,7 +326,6 @@ BUILTIN(ArrayPop) {
return top;
}
-BUILTIN_END
// -----------------------------------------------------------------------------
@@ -320,20 +380,20 @@ static inline Object* TypeCheck(int argc,
}
-BUILTIN(HandleApiCall) {
- HandleScope scope;
- bool is_construct = CalledAsConstructor();
+template <bool is_construct>
+static Object* HandleApiCallHelper(
+ BuiltinArguments<NEEDS_CALLED_FUNCTION> args) {
+ ASSERT(is_construct == CalledAsConstructor());
- // TODO(428): Remove use of static variable, handle API callbacks directly.
- Handle<JSFunction> function =
- Handle<JSFunction>(JSFunction::cast(Builtins::builtin_passed_function));
+ HandleScope scope;
+ Handle<JSFunction> function = args.called_function();
if (is_construct) {
Handle<FunctionTemplateInfo> desc =
Handle<FunctionTemplateInfo>(
FunctionTemplateInfo::cast(function->shared()->function_data()));
bool pending_exception = false;
- Factory::ConfigureInstance(desc, Handle<JSObject>::cast(receiver),
+ Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
&pending_exception);
ASSERT(Top::has_pending_exception() == pending_exception);
if (pending_exception) return Failure::Exception();
@@ -359,15 +419,13 @@ BUILTIN(HandleApiCall) {
Object* data_obj = call_data->data();
Object* result;
- v8::Local<v8::Object> self =
- v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
Handle<Object> data_handle(data_obj);
v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
ASSERT(raw_holder->IsJSObject());
v8::Local<v8::Function> callee = v8::Utils::ToLocal(function);
Handle<JSObject> holder_handle(JSObject::cast(raw_holder));
v8::Local<v8::Object> holder = v8::Utils::ToLocal(holder_handle);
- LOG(ApiObjectAccess("call", JSObject::cast(*receiver)));
+ LOG(ApiObjectAccess("call", JSObject::cast(*args.receiver())));
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
data,
holder,
@@ -395,16 +453,26 @@ BUILTIN(HandleApiCall) {
if (!is_construct || result->IsJSObject()) return result;
}
- return *receiver;
+ return *args.receiver();
+}
+
+
+BUILTIN(HandleApiCall) {
+ return HandleApiCallHelper<false>(args);
+}
+
+
+BUILTIN(HandleApiCallConstruct) {
+ return HandleApiCallHelper<true>(args);
}
-BUILTIN_END
// Helper function to handle calls to non-function objects created through the
// API. The object can be called as either a constructor (using new) or just as
// a function (without new).
-static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
- Arguments args) {
+static Object* HandleApiCallAsFunctionOrConstructor(
+ bool is_construct_call,
+ BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
// Non-functions are never called as constructors. Even if this is an object
// called as a constructor the delegate call is not a construct call.
ASSERT(!CalledAsConstructor());
@@ -412,7 +480,7 @@ static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
Handle<Object> receiver = args.at<Object>(0);
// Get the object called.
- JSObject* obj = JSObject::cast(*receiver);
+ JSObject* obj = JSObject::cast(*args.receiver());
// Get the invocation callback from the function descriptor that was
// used to create the called object.
@@ -432,12 +500,12 @@ static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
Object* result;
{ HandleScope scope;
v8::Local<v8::Object> self =
- v8::Utils::ToLocal(Handle<JSObject>::cast(receiver));
+ v8::Utils::ToLocal(Handle<JSObject>::cast(args.receiver()));
Handle<Object> data_handle(data_obj);
v8::Local<v8::Value> data = v8::Utils::ToLocal(data_handle);
Handle<JSFunction> callee_handle(constructor);
v8::Local<v8::Function> callee = v8::Utils::ToLocal(callee_handle);
- LOG(ApiObjectAccess("call non-function", JSObject::cast(*receiver)));
+ LOG(ApiObjectAccess("call non-function", JSObject::cast(*args.receiver())));
v8::Arguments new_args = v8::ImplementationUtilities::NewArguments(
data,
self,
@@ -471,7 +539,6 @@ static Object* HandleApiCallAsFunctionOrConstructor(bool is_construct_call,
BUILTIN(HandleApiCallAsFunction) {
return HandleApiCallAsFunctionOrConstructor(false, args);
}
-BUILTIN_END
// Handle calls to non-function objects created through the API. This delegate
@@ -479,14 +546,6 @@ BUILTIN_END
BUILTIN(HandleApiCallAsConstructor) {
return HandleApiCallAsFunctionOrConstructor(true, args);
}
-BUILTIN_END
-
-
-// TODO(1238487): This is a nasty hack. We need to improve the way we
-// call builtins considerable to get rid of this and the hairy macros
-// in builtins.cc.
-Object* Builtins::builtin_passed_function;
-
static void Generate_LoadIC_ArrayLength(MacroAssembler* masm) {
@@ -708,7 +767,7 @@ static void Generate_StubNoRegisters_DebugBreak(MacroAssembler* masm) {
Object* Builtins::builtins_[builtin_count] = { NULL, };
const char* Builtins::names_[builtin_count] = { NULL, };
-#define DEF_ENUM_C(name) FUNCTION_ADDR(Builtin_##name),
+#define DEF_ENUM_C(name, ignore) FUNCTION_ADDR(Builtin_##name),
Address Builtins::c_functions_[cfunction_count] = {
BUILTIN_LIST_C(DEF_ENUM_C)
};
@@ -739,14 +798,16 @@ void Builtins::Setup(bool create_heap_objects) {
const char* s_name; // name is only used for generating log information.
int name;
Code::Flags flags;
+ BuiltinExtraArguments extra_args;
};
-#define DEF_FUNCTION_PTR_C(name) \
- { FUNCTION_ADDR(Generate_Adaptor), \
- FUNCTION_ADDR(Builtin_##name), \
- #name, \
- c_##name, \
- Code::ComputeFlags(Code::BUILTIN) \
+#define DEF_FUNCTION_PTR_C(name, extra_args) \
+ { FUNCTION_ADDR(Generate_Adaptor), \
+ FUNCTION_ADDR(Builtin_##name), \
+ #name, \
+ c_##name, \
+ Code::ComputeFlags(Code::BUILTIN), \
+ extra_args \
},
#define DEF_FUNCTION_PTR_A(name, kind, state) \
@@ -754,7 +815,8 @@ void Builtins::Setup(bool create_heap_objects) {
NULL, \
#name, \
name, \
- Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state) \
+ Code::ComputeFlags(Code::kind, NOT_IN_LOOP, state), \
+ NO_EXTRA_ARGUMENTS \
},
// Define array of pointers to generators and C builtin functions.
@@ -763,7 +825,8 @@ void Builtins::Setup(bool create_heap_objects) {
BUILTIN_LIST_A(DEF_FUNCTION_PTR_A)
BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A)
// Terminator:
- { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0) }
+ { NULL, NULL, NULL, builtin_count, static_cast<Code::Flags>(0),
+ NO_EXTRA_ARGUMENTS }
};
#undef DEF_FUNCTION_PTR_C
@@ -779,12 +842,12 @@ void Builtins::Setup(bool create_heap_objects) {
if (create_heap_objects) {
MacroAssembler masm(buffer, sizeof buffer);
// Generate the code/adaptor.
- typedef void (*Generator)(MacroAssembler*, int);
+ typedef void (*Generator)(MacroAssembler*, int, BuiltinExtraArguments);
Generator g = FUNCTION_CAST<Generator>(functions[i].generator);
// We pass all arguments to the generator, but it may not use all of
// them. This works because the first arguments are on top of the
// stack.
- g(&masm, functions[i].name);
+ g(&masm, functions[i].name, functions[i].extra_args);
// Move the code into the object heap.
CodeDesc desc;
masm.GetCode(&desc);
« no previous file with comments | « src/builtins.h ('k') | src/factory.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698