| 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);
|
|
|