escargot/src/runtime/NativeFunctionObject.cpp
MuHong Byun e2f1c3f47d Fix LGPL License verison typo (2.0 -> 2.1)
Signed-off-by: MuHong Byun <mh.byun@samsung.com>
2020-03-10 11:35:20 +09:00

195 lines
8.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* Copyright (c) 2019-present Samsung Electronics Co., Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
* USA
*/
#include "Escargot.h"
#include "NativeFunctionObject.h"
#include "FunctionObjectInlines.h"
namespace Escargot {
// function for derived classes. derived class MUST initlize member variable of FunctionObject.
NativeFunctionObject::NativeFunctionObject(ExecutionState& state, size_t defaultSpace)
: FunctionObject(state, defaultSpace)
{
}
NativeFunctionObject::NativeFunctionObject(ExecutionState& state, CodeBlock* codeBlock)
: FunctionObject(state, codeBlock->isNativeFunctionConstructor() ? (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3) : (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2))
{
m_codeBlock = codeBlock;
initStructureAndValues(state, m_codeBlock->isNativeFunctionConstructor(), false, false);
Object::setPrototypeForIntrinsicObjectCreation(state, state.context()->globalObject()->functionPrototype());
if (NativeFunctionObject::isConstructor())
m_structure = state.context()->defaultStructureForBuiltinFunctionObject();
ASSERT(FunctionObject::codeBlock()->hasCallNativeFunctionCode());
}
NativeFunctionObject::NativeFunctionObject(ExecutionState& state, NativeFunctionInfo info)
: FunctionObject(state, info.m_isConstructor ? (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3) : (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2))
{
m_codeBlock = new CodeBlock(state.context(), info);
initStructureAndValues(state, m_codeBlock->isNativeFunctionConstructor(), false, false);
Object::setPrototypeForIntrinsicObjectCreation(state, state.context()->globalObject()->functionPrototype());
}
NativeFunctionObject::NativeFunctionObject(ExecutionState& state, CodeBlock* codeBlock, ForGlobalBuiltin)
: FunctionObject(state, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2)
{
m_codeBlock = codeBlock;
ASSERT(!NativeFunctionObject::isConstructor());
initStructureAndValues(state, m_codeBlock->isNativeFunctionConstructor(), false, false);
}
NativeFunctionObject::NativeFunctionObject(ExecutionState& state, CodeBlock* codeBlock, ForBuiltinConstructor)
: FunctionObject(state, codeBlock->isNativeFunctionConstructor() ? (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3) : (ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2))
{
m_codeBlock = codeBlock;
initStructureAndValues(state, codeBlock->isNativeFunctionConstructor(), false, false);
Object::setPrototypeForIntrinsicObjectCreation(state, state.context()->globalObject()->functionPrototype());
if (NativeFunctionObject::isConstructor())
m_structure = state.context()->defaultStructureForBuiltinFunctionObject();
ASSERT(FunctionObject::codeBlock()->hasCallNativeFunctionCode());
}
NativeFunctionObject::NativeFunctionObject(ExecutionState& state, NativeFunctionInfo info, ForBuiltinConstructor)
: FunctionObject(state, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 3)
{
m_codeBlock = new CodeBlock(state.context(), info);
initStructureAndValues(state, m_codeBlock->isNativeFunctionConstructor(), false, false);
Object::setPrototypeForIntrinsicObjectCreation(state, state.context()->globalObject()->functionPrototype());
m_structure = state.context()->defaultStructureForBuiltinFunctionObject();
ASSERT(NativeFunctionObject::isConstructor());
ASSERT(codeBlock()->hasCallNativeFunctionCode());
}
NativeFunctionObject::NativeFunctionObject(ExecutionState& state, NativeFunctionInfo info, ForBuiltinProxyConstructor)
: FunctionObject(state, ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 2)
{
m_codeBlock = new CodeBlock(state.context(), info);
// The Proxy constructor does not have a prototype property
m_structure = state.context()->defaultStructureForNotConstructorFunctionObject();
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 0] = (Value(m_codeBlock->functionName().string()));
m_values[ESCARGOT_OBJECT_BUILTIN_PROPERTY_NUMBER + 1] = (Value(m_codeBlock->functionLength()));
Object::setPrototypeForIntrinsicObjectCreation(state, state.context()->globalObject()->functionPrototype());
ASSERT(NativeFunctionObject::isConstructor());
ASSERT(codeBlock()->hasCallNativeFunctionCode());
}
bool NativeFunctionObject::isConstructor() const
{
return m_codeBlock->isNativeFunctionConstructor();
}
template <bool isConstruct>
Value NativeFunctionObject::processNativeFunctionCall(ExecutionState& state, const Value& receiverSrc, const size_t argc, Value* argv, Object* newTarget)
{
volatile int sp;
size_t currentStackBase = (size_t)&sp;
#ifdef STACK_GROWS_DOWN
if (UNLIKELY(state.stackLimit() > currentStackBase)) {
#else
if (UNLIKELY(state.stackLimit() < currentStackBase)) {
#endif
ErrorObject::throwBuiltinError(state, ErrorObject::RangeError, "Maximum call stack size exceeded");
}
Context* ctx = m_codeBlock->context();
bool isStrict = m_codeBlock->isStrict();
CallNativeFunctionData* code = m_codeBlock->nativeFunctionData();
size_t len = m_codeBlock->functionLength();
if (argc < len) {
Value* newArgv = (Value*)alloca(sizeof(Value) * len);
for (size_t i = 0; i < argc; i++) {
newArgv[i] = argv[i];
}
for (size_t i = argc; i < len; i++) {
newArgv[i] = Value();
}
argv = newArgv;
}
Value receiver = receiverSrc;
ExecutionState newState(ctx, &state, this, argc, argv, isStrict);
if (!isConstruct) {
// prepare receiver
if (UNLIKELY(!isStrict)) {
if (receiver.isUndefinedOrNull()) {
receiver = ctx->globalObject();
} else {
receiver = receiver.toObject(newState);
}
}
}
if (isConstruct) {
Value result = code->m_fn(newState, receiver, argc, argv, isConstruct);
if (UNLIKELY(!result.isObject())) {
ErrorObject::throwBuiltinError(newState, ErrorObject::TypeError, "Native Constructor must returns constructed new object");
}
// if newTarget is differ with this function object, ex) class A extends Array{}; new A();
if (newTarget != this) {
// set prototype for native object
Object* thisArgument = result.asObject();
// Let thisArgument be OrdinaryCreateFromConstructor(newTarget, "%ObjectPrototype%").
// OrdinaryCreateFromConstructor -> Let proto be GetPrototypeFromConstructor(constructor, intrinsicDefaultProto).
// OrdinaryCreateFromConstructor -> GetPrototypeFromConstructor -> Let proto be Get(constructor, "prototype").
Value proto = newTarget->get(newState, ObjectPropertyName(newState.context()->staticStrings().prototype)).value(newState, newTarget);
// OrdinaryCreateFromConstructor -> GetPrototypeFromConstructor -> If Type(proto) is not Object, then
// OrdinaryCreateFromConstructor -> GetPrototypeFromConstructor -> Let realm be GetFunctionRealm(constructor).
// OrdinaryCreateFromConstructor -> GetPrototypeFromConstructor -> ReturnIfAbrupt(realm).
// OrdinaryCreateFromConstructor -> GetPrototypeFromConstructor -> Let proto be realms intrinsic object named intrinsicDefaultProto.
if (!proto.isObject()) {
proto = ctx->globalObject()->objectPrototype();
}
thisArgument->setPrototype(state, proto);
}
return result;
} else {
return code->m_fn(newState, receiver, argc, argv, isConstruct);
}
}
Value NativeFunctionObject::call(ExecutionState& state, const Value& thisValue, const size_t argc, NULLABLE Value* argv)
{
ASSERT(codeBlock()->hasCallNativeFunctionCode());
return processNativeFunctionCall<false>(state, thisValue, argc, argv, nullptr);
}
Object* NativeFunctionObject::construct(ExecutionState& state, const size_t argc, NULLABLE Value* argv, Object* newTarget)
{
// Assert: Type(newTarget) is Object.
ASSERT(newTarget->isObject());
ASSERT(newTarget->isConstructor());
ASSERT(codeBlock()->hasCallNativeFunctionCode());
Value result = processNativeFunctionCall<true>(state, Value(), argc, argv, newTarget);
return result.asObject();
}
}