1/*
2 * Copyright (C) 2009-2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "CallFrameClosure.h"
29#include "ExceptionHelpers.h"
30#include "JSFunction.h"
31#include "Interpreter.h"
32#include "ProtoCallFrame.h"
33#include "VMEntryScope.h"
34#include "VMInlines.h"
35#include <wtf/ForbidHeapAllocation.h>
36
37namespace JSC {
38 class CachedCall {
39 WTF_MAKE_NONCOPYABLE(CachedCall);
40 WTF_FORBID_HEAP_ALLOCATION;
41 public:
42 CachedCall(JSGlobalObject* globalObject, CallFrame* callFrame, JSFunction* function, int argumentCount)
43 : m_valid(false)
44 , m_vm(globalObject->vm())
45 , m_interpreter(m_vm.interpreter)
46 , m_entryScope(m_vm, function->scope()->globalObject(m_vm))
47 {
48 VM& vm = m_entryScope.vm();
49 auto scope = DECLARE_THROW_SCOPE(vm);
50
51 ASSERT(!function->isHostFunctionNonInline());
52 if (LIKELY(vm.isSafeToRecurseSoft())) {
53 m_arguments.ensureCapacity(argumentCount);
54 if (LIKELY(!m_arguments.hasOverflowed()))
55 m_closure = m_interpreter->prepareForRepeatCall(function->jsExecutable(), callFrame, &m_protoCallFrame, function, argumentCount + 1, function->scope(), m_arguments);
56 else
57 throwOutOfMemoryError(globalObject, scope);
58 } else
59 throwStackOverflowError(globalObject, scope);
60 m_valid = !scope.exception();
61 }
62
63 ALWAYS_INLINE JSValue call()
64 {
65 ASSERT(m_valid);
66 ASSERT(m_arguments.size() == static_cast<size_t>(m_protoCallFrame.argumentCount()));
67 return m_interpreter->execute(m_closure);
68 }
69 void setThis(JSValue v) { m_protoCallFrame.setThisValue(v); }
70
71 void clearArguments() { m_arguments.clear(); }
72 void appendArgument(JSValue v) { m_arguments.append(v); }
73 bool hasOverflowedArguments() { return m_arguments.hasOverflowed(); }
74
75 private:
76 bool m_valid;
77 VM& m_vm;
78 Interpreter* m_interpreter;
79 VMEntryScope m_entryScope;
80 ProtoCallFrame m_protoCallFrame;
81 MarkedArgumentBuffer m_arguments;
82 CallFrameClosure m_closure;
83 };
84}
85