// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/builtins/builtins-utils-inl.h"
#include "src/builtins/builtins.h"
#include "src/objects/elements.h"

#include "src/logging/counters.h"
#include "src/objects/objects-inl.h"

namespace v8 {
namespace internal {

namespace {
enum UncurryThisFunctionContextSlot {
  kFunctionSlot = Context::MIN_CONTEXT_SLOTS,
  kFunctionContextLength,
};
}  // namespace

// These functions are key for safe meta-programming:
// http://wiki.ecmascript.org/doku.php?id=conventions:safe_meta_programming
//
// Technically they could all be derived from combinations of
// Function.prototype.{bind,call,apply} but that introduces lots of layers of
// indirection.
//
// Equivalent to:
//
//   function uncurryThis(func) {
//     return function(thisArg, ...args) {
//       return %reflect_apply(func, thisArg, args);
//     };
//   };
//
BUILTIN(ExtrasUtilsUncurryThis) {
  HandleScope scope(isolate);

  DCHECK_EQ(2, args.length());
  Handle<JSFunction> function = args.at<JSFunction>(1);
  Handle<NativeContext> native_context(isolate->context().native_context(),
                                       isolate);
  Handle<Context> context = isolate->factory()->NewBuiltinContext(
      native_context,
      static_cast<int>(UncurryThisFunctionContextSlot::kFunctionContextLength));

  context->set(static_cast<int>(UncurryThisFunctionContextSlot::kFunctionSlot),
               *function);

  Handle<SharedFunctionInfo> info =
      isolate->factory()->NewSharedFunctionInfoForBuiltin(
          isolate->factory()->empty_string(),
          Builtins::kExtrasUtilsCallReflectApply, kNormalFunction);
  info->DontAdaptArguments();

  Handle<Map> map = isolate->strict_function_without_prototype_map();
  Handle<JSFunction> new_bound_function =
      isolate->factory()->NewFunctionFromSharedFunctionInfo(map, info, context);

  return *new_bound_function;
}

BUILTIN(ExtrasUtilsCallReflectApply) {
  HandleScope scope(isolate);
  Handle<Context> context(isolate->context(), isolate);
  Handle<NativeContext> native_context(isolate->context().native_context(),
                                       isolate);
  Handle<JSFunction> function(
      JSFunction::cast(context->get(
          static_cast<int>(UncurryThisFunctionContextSlot::kFunctionSlot))),
      isolate);

  Handle<Object> this_arg = args.at(1);

  int const rest_args_atart = 2;
  Arguments argv(args.length() - rest_args_atart,
                 args.address_of_arg_at(rest_args_atart));
  Handle<JSArray> rest_args_array = isolate->factory()->NewJSArray(0);
  RETURN_FAILURE_ON_EXCEPTION(
      isolate, ArrayConstructInitializeElements(rest_args_array, &argv));

  Handle<Object> reflect_apply_args[] = {function, this_arg, rest_args_array};
  Handle<JSFunction> reflect_apply(native_context->reflect_apply(), isolate);
  RETURN_RESULT_OR_FAILURE(
      isolate,
      Execution::Call(isolate, reflect_apply,
                      isolate->factory()->undefined_value(),
                      arraysize(reflect_apply_args), reflect_apply_args));
}

}  // namespace internal
}  // namespace v8
