// Copyright 2014 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/runtime/runtime-utils.h" #include "src/accessors.h" #include "src/arguments.h" #include "src/compiler.h" #include "src/frames-inl.h" #include "src/isolate-inl.h" #include "src/messages.h" #include "src/profiler/cpu-profiler.h" namespace v8 { namespace internal { RUNTIME_FUNCTION(Runtime_FunctionGetName) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, f, 0); return f->shared()->name(); } RUNTIME_FUNCTION(Runtime_FunctionSetName) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, f, 0); CONVERT_ARG_HANDLE_CHECKED(String, name, 1); name = String::Flatten(name); f->shared()->set_name(*name); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_FunctionRemovePrototype) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, f, 0); RUNTIME_ASSERT(f->RemovePrototype()); f->shared()->set_construct_stub( *isolate->builtins()->ConstructedNonConstructable()); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_FunctionGetScript) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); if (function->IsJSBoundFunction()) return isolate->heap()->undefined_value(); Handle<Object> script(Handle<JSFunction>::cast(function)->shared()->script(), isolate); if (!script->IsScript()) return isolate->heap()->undefined_value(); return *Script::GetWrapper(Handle<Script>::cast(script)); } RUNTIME_FUNCTION(Runtime_FunctionGetSourceCode) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); if (function->IsJSBoundFunction()) return isolate->heap()->undefined_value(); return *Handle<JSFunction>::cast(function)->shared()->GetSourceCode(); } RUNTIME_FUNCTION(Runtime_FunctionGetScriptSourcePosition) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, fun, 0); int pos = fun->shared()->start_position(); return Smi::FromInt(pos); } RUNTIME_FUNCTION(Runtime_FunctionGetPositionForOffset) { SealHandleScope shs(isolate); DCHECK(args.length() == 2); CONVERT_ARG_CHECKED(AbstractCode, abstract_code, 0); CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]); return Smi::FromInt(abstract_code->SourcePosition(offset)); } RUNTIME_FUNCTION(Runtime_FunctionSetInstanceClassName) { SealHandleScope shs(isolate); DCHECK(args.length() == 2); CONVERT_ARG_CHECKED(JSFunction, fun, 0); CONVERT_ARG_CHECKED(String, name, 1); fun->shared()->set_instance_class_name(name); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_FunctionSetLength) { SealHandleScope shs(isolate); DCHECK(args.length() == 2); CONVERT_ARG_CHECKED(JSFunction, fun, 0); CONVERT_SMI_ARG_CHECKED(length, 1); RUNTIME_ASSERT((length & 0xC0000000) == 0xC0000000 || (length & 0xC0000000) == 0x0); fun->shared()->set_length(length); return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_FunctionSetPrototype) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, fun, 0); CONVERT_ARG_HANDLE_CHECKED(Object, value, 1); RUNTIME_ASSERT(fun->IsConstructor()); RETURN_FAILURE_ON_EXCEPTION(isolate, Accessors::FunctionSetPrototype(fun, value)); return args[0]; // return TOS } RUNTIME_FUNCTION(Runtime_FunctionIsAPIFunction) { SealHandleScope shs(isolate); DCHECK(args.length() == 1); CONVERT_ARG_CHECKED(JSFunction, f, 0); return isolate->heap()->ToBoolean(f->shared()->IsApiFunction()); } RUNTIME_FUNCTION(Runtime_SetCode) { HandleScope scope(isolate); DCHECK(args.length() == 2); CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0); CONVERT_ARG_HANDLE_CHECKED(JSFunction, source, 1); Handle<SharedFunctionInfo> target_shared(target->shared()); Handle<SharedFunctionInfo> source_shared(source->shared()); if (!Compiler::Compile(source, KEEP_EXCEPTION)) { return isolate->heap()->exception(); } // Mark both, the source and the target, as un-flushable because the // shared unoptimized code makes them impossible to enqueue in a list. DCHECK(target_shared->code()->gc_metadata() == NULL); DCHECK(source_shared->code()->gc_metadata() == NULL); target_shared->set_dont_flush(true); source_shared->set_dont_flush(true); // Set the code, scope info, formal parameter count, and the length // of the target shared function info. target_shared->ReplaceCode(source_shared->code()); target_shared->set_scope_info(source_shared->scope_info()); target_shared->set_length(source_shared->length()); target_shared->set_feedback_vector(source_shared->feedback_vector()); target_shared->set_internal_formal_parameter_count( source_shared->internal_formal_parameter_count()); target_shared->set_start_position_and_type( source_shared->start_position_and_type()); target_shared->set_end_position(source_shared->end_position()); bool was_native = target_shared->native(); target_shared->set_compiler_hints(source_shared->compiler_hints()); target_shared->set_opt_count_and_bailout_reason( source_shared->opt_count_and_bailout_reason()); target_shared->set_native(was_native); target_shared->set_profiler_ticks(source_shared->profiler_ticks()); SharedFunctionInfo::SetScript( target_shared, Handle<Object>(source_shared->script(), isolate)); // Set the code of the target function. target->ReplaceCode(source_shared->code()); DCHECK(target->next_function_link()->IsUndefined()); // Make sure we get a fresh copy of the literal vector to avoid cross // context contamination. Handle<Context> context(source->context()); target->set_context(*context); int number_of_literals = source->NumberOfLiterals(); Handle<LiteralsArray> literals = LiteralsArray::New(isolate, handle(target_shared->feedback_vector()), number_of_literals, TENURED); target->set_literals(*literals); if (isolate->logger()->is_logging_code_events() || isolate->cpu_profiler()->is_profiling()) { isolate->logger()->LogExistingFunction(source_shared, Handle<Code>(source_shared->code())); } return *target; } // Set the native flag on the function. // This is used to decide if we should transform null and undefined // into the global object when doing call and apply. RUNTIME_FUNCTION(Runtime_SetNativeFlag) { SealHandleScope shs(isolate); RUNTIME_ASSERT(args.length() == 1); CONVERT_ARG_CHECKED(Object, object, 0); if (object->IsJSFunction()) { JSFunction* func = JSFunction::cast(object); func->shared()->set_native(true); } return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_IsConstructor) { SealHandleScope shs(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_CHECKED(Object, object, 0); return isolate->heap()->ToBoolean(object->IsConstructor()); } RUNTIME_FUNCTION(Runtime_SetForceInlineFlag) { SealHandleScope shs(isolate); RUNTIME_ASSERT(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, object, 0); if (object->IsJSFunction()) { JSFunction* func = JSFunction::cast(*object); func->shared()->set_force_inline(true); } return isolate->heap()->undefined_value(); } RUNTIME_FUNCTION(Runtime_Call) { HandleScope scope(isolate); DCHECK_LE(2, args.length()); int const argc = args.length() - 2; CONVERT_ARG_HANDLE_CHECKED(JSReceiver, target, 0); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); ScopedVector<Handle<Object>> argv(argc); for (int i = 0; i < argc; ++i) { argv[i] = args.at<Object>(2 + i); } Handle<Object> result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, Execution::Call(isolate, target, receiver, argc, argv.start())); return *result; } RUNTIME_FUNCTION(Runtime_TailCall) { HandleScope scope(isolate); DCHECK_LE(2, args.length()); int const argc = args.length() - 2; CONVERT_ARG_HANDLE_CHECKED(JSReceiver, target, 0); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); ScopedVector<Handle<Object>> argv(argc); for (int i = 0; i < argc; ++i) { argv[i] = args.at<Object>(2 + i); } Handle<Object> result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, Execution::Call(isolate, target, receiver, argc, argv.start())); return *result; } RUNTIME_FUNCTION(Runtime_Apply) { HandleScope scope(isolate); DCHECK(args.length() == 5); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, fun, 0); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, arguments, 2); CONVERT_INT32_ARG_CHECKED(offset, 3); CONVERT_INT32_ARG_CHECKED(argc, 4); RUNTIME_ASSERT(offset >= 0); // Loose upper bound to allow fuzzing. We'll most likely run out of // stack space before hitting this limit. static int kMaxArgc = 1000000; RUNTIME_ASSERT(argc >= 0 && argc <= kMaxArgc); // If there are too many arguments, allocate argv via malloc. const int argv_small_size = 10; Handle<Object> argv_small_buffer[argv_small_size]; base::SmartArrayPointer<Handle<Object> > argv_large_buffer; Handle<Object>* argv = argv_small_buffer; if (argc > argv_small_size) { argv = new Handle<Object>[argc]; if (argv == NULL) return isolate->StackOverflow(); argv_large_buffer = base::SmartArrayPointer<Handle<Object> >(argv); } for (int i = 0; i < argc; ++i) { ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, argv[i], Object::GetElement(isolate, arguments, offset + i)); } Handle<Object> result; ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, result, Execution::Call(isolate, fun, receiver, argc, argv)); return *result; } // ES6 section 9.2.1.2, OrdinaryCallBindThis for sloppy callee. RUNTIME_FUNCTION(Runtime_ConvertReceiver) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0); if (receiver->IsNull() || receiver->IsUndefined()) { return isolate->global_proxy(); } return *Object::ToObject(isolate, receiver).ToHandleChecked(); } RUNTIME_FUNCTION(Runtime_IsFunction) { SealHandleScope shs(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_CHECKED(Object, object, 0); return isolate->heap()->ToBoolean(object->IsFunction()); } RUNTIME_FUNCTION(Runtime_ThrowStrongModeTooFewArguments) { HandleScope scope(isolate); DCHECK(args.length() == 0); THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(MessageTemplate::kStrongArity)); } RUNTIME_FUNCTION(Runtime_FunctionToString) { HandleScope scope(isolate); DCHECK_EQ(1, args.length()); CONVERT_ARG_HANDLE_CHECKED(JSReceiver, function, 0); return function->IsJSBoundFunction() ? *JSBoundFunction::ToString( Handle<JSBoundFunction>::cast(function)) : *JSFunction::ToString(Handle<JSFunction>::cast(function)); } } // namespace internal } // namespace v8