Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update isCallable check function according to call operation #290

Merged
merged 1 commit into from
Jun 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/api/EscargotPublic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1292,7 +1292,7 @@ ValueRef* FunctionObjectRef::call(ExecutionStateRef* state, ValueRef* receiver,
for (size_t i = 0; i < argc; i++) {
newArgv[i] = toImpl(argv[i]);
}
return toRef(o->call(*toImpl(state), toImpl(receiver), argc, newArgv));
return toRef(Object::call(*toImpl(state), o, toImpl(receiver), argc, newArgv));
}

static void markEvalToCodeblock(InterpretedCodeBlock* cb)
Expand Down Expand Up @@ -1622,6 +1622,11 @@ bool ValueRef::isFunction() const
return Value(SmallValue::fromPayload(this)).isFunction();
}

bool ValueRef::isCallable() const
{
return Value(SmallValue::fromPayload(this)).isCallable();
}

bool ValueRef::toBoolean(ExecutionStateRef* es)
{
ExecutionState* esi = toImpl(es);
Expand Down
1 change: 1 addition & 0 deletions src/api/EscargotPublic.h
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,7 @@ class EXPORT ValueRef {
bool isString() const;
bool isObject() const;
bool isFunction() const;
bool isCallable() const;
bool isUndefinedOrNull() const
{
return isUndefined() || isNull();
Expand Down
22 changes: 12 additions & 10 deletions src/interpreter/ByteCodeInterpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState& state, ByteCodeBlock* byteC
{
CallFunction* code = (CallFunction*)programCounter;
const Value& callee = registerFile[code->m_calleeIndex];
registerFile[code->m_resultIndex] = FunctionObject::call(state, callee, Value(), code->m_argumentCount, &registerFile[code->m_argumentsStartIndex]);
registerFile[code->m_resultIndex] = Object::call(state, callee, Value(), code->m_argumentCount, &registerFile[code->m_argumentsStartIndex]);
ADD_PROGRAM_COUNTER(CallFunction);
NEXT_INSTRUCTION();
}
Expand All @@ -569,7 +569,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState& state, ByteCodeBlock* byteC
CallFunctionWithReceiver* code = (CallFunctionWithReceiver*)programCounter;
const Value& callee = registerFile[code->m_calleeIndex];
const Value& receiver = registerFile[code->m_receiverIndex];
registerFile[code->m_resultIndex] = FunctionObject::call(state, callee, receiver, code->m_argumentCount, &registerFile[code->m_argumentsStartIndex]);
registerFile[code->m_resultIndex] = Object::call(state, callee, receiver, code->m_argumentCount, &registerFile[code->m_argumentsStartIndex]);
ADD_PROGRAM_COUNTER(CallFunctionWithReceiver);
NEXT_INSTRUCTION();
}
Expand Down Expand Up @@ -1268,7 +1268,7 @@ Value ByteCodeInterpreter::interpret(ExecutionState& state, ByteCodeBlock* byteC
const Value& receiver = code->m_receiverIndex == REGISTER_LIMIT ? Value() : registerFile[code->m_receiverIndex];
ValueVector spreadArgs;
spreadFunctionArguments(state, &registerFile[code->m_argumentsStartIndex], code->m_argumentCount, spreadArgs);
registerFile[code->m_resultIndex] = FunctionObject::call(state, callee, receiver, spreadArgs.size(), spreadArgs.data());
registerFile[code->m_resultIndex] = Object::call(state, callee, receiver, spreadArgs.size(), spreadArgs.data());
ADD_PROGRAM_COUNTER(CallFunctionWithSpreadElement);
NEXT_INSTRUCTION();
}
Expand Down Expand Up @@ -1500,7 +1500,7 @@ NEVER_INLINE Object* ByteCodeInterpreter::newOperation(ExecutionState& state, co
if (callee.isConstructor() == false) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_Not_Constructor);
}
return FunctionObject::construct(state, callee, argc, argv);
return Object::construct(state, callee, argc, argv);
}

// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-instanceofoperator
Expand All @@ -1517,7 +1517,7 @@ NEVER_INLINE Value ByteCodeInterpreter::instanceOfOperation(ExecutionState& stat
if (!instOfHandler.isUndefined()) {
// Return ToBoolean(Call(instOfHandler, C, «O»)).
Value arg[1] = { left };
return Value(FunctionObject::call(state, instOfHandler, right, 1, arg).toBoolean(state));
return Value(Object::call(state, instOfHandler, right, 1, arg).toBoolean(state));
}
#endif
// If IsCallable(C) is false, throw a TypeError exception.
Expand Down Expand Up @@ -2193,7 +2193,7 @@ NEVER_INLINE void ByteCodeInterpreter::evalOperation(ExecutionState& state, Call
thisValue = env->record()->asObjectEnvironmentRecord()->bindingObject();
}
}
registerFile[code->m_resultIndex] = FunctionObject::call(state, eval, thisValue, argc, argv);
registerFile[code->m_resultIndex] = Object::call(state, eval, thisValue, argc, argv);
}
}

Expand Down Expand Up @@ -2396,9 +2396,9 @@ NEVER_INLINE Value ByteCodeInterpreter::callFunctionInWithScope(ExecutionState&
if (code->m_hasSpreadElement) {
ValueVector spreadArgs;
spreadFunctionArguments(state, argv, code->m_argumentCount, spreadArgs);
return FunctionObject::call(state, callee, receiverObj, spreadArgs.size(), spreadArgs.data());
return Object::call(state, callee, receiverObj, spreadArgs.size(), spreadArgs.data());
}
return FunctionObject::call(state, callee, receiverObj, code->m_argumentCount, argv);
return Object::call(state, callee, receiverObj, code->m_argumentCount, argv);
}

void ByteCodeInterpreter::spreadFunctionArguments(ExecutionState& state, const Value* argv, const size_t argc, ValueVector& argVector)
Expand Down Expand Up @@ -2458,7 +2458,7 @@ Value ByteCodeInterpreter::yieldDelegateOperation(ExecutionState& state, Value*
return nextValue;
}

Value innerResult = FunctionObject::call(state, ret, iterator, 1, &nextValue);
Value innerResult = Object::call(state, ret, iterator, 1, &nextValue);

if (innerResult.isObject() == false) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "IteratorResult is not an object");
Expand All @@ -2479,7 +2479,7 @@ Value ByteCodeInterpreter::yieldDelegateOperation(ExecutionState& state, Value*

if (throwMethod.isUndefined() == false) {
Value innerResult;
innerResult = FunctionObject::call(state, throwMethod, iterator, 1, &nextValue);
innerResult = Object::call(state, throwMethod, iterator, 1, &nextValue);
if (innerResult.isObject() == false) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, "IteratorResult is not an object");
}
Expand Down Expand Up @@ -2559,6 +2559,7 @@ NEVER_INLINE void ByteCodeInterpreter::declareFunctionDeclarations(ExecutionStat

NEVER_INLINE void ByteCodeInterpreter::defineObjectGetter(ExecutionState& state, ObjectDefineGetter* code, Value* registerFile)
{
// FIXME: FunctionObject
FunctionObject* fn = registerFile[code->m_objectPropertyValueRegisterIndex].asFunction();
String* pName = registerFile[code->m_objectPropertyNameRegisterIndex].toString(state);
StringBuilder builder;
Expand All @@ -2574,6 +2575,7 @@ NEVER_INLINE void ByteCodeInterpreter::defineObjectGetter(ExecutionState& state,

NEVER_INLINE void ByteCodeInterpreter::defineObjectSetter(ExecutionState& state, ObjectDefineSetter* code, Value* registerFile)
{
// FIXME: FunctionObject
FunctionObject* fn = registerFile[code->m_objectPropertyValueRegisterIndex].asFunction();
String* pName = registerFile[code->m_objectPropertyNameRegisterIndex].toString(state);
StringBuilder builder;
Expand Down
4 changes: 2 additions & 2 deletions src/runtime/BoundFunctionObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Value BoundFunctionObject::call(ExecutionState& state, const Value& thisValue, c
}

// Return Call(target, boundThis, args).
return FunctionObject::call(state, m_boundTargetFunction, m_boundThis, mergedArgc, mergedArgv);
return Object::call(state, m_boundTargetFunction, m_boundThis, mergedArgc, mergedArgv);
}

// https://www.ecma-international.org/ecma-262/6.0/#sec-bound-function-exotic-objects-construct-argumentslist-newtarget
Expand All @@ -95,6 +95,6 @@ Object* BoundFunctionObject::construct(ExecutionState& state, const size_t calle
Value newConstructTarget = (Value(this) == Value(newTarget)) ? Value(m_boundTargetFunction) : newTarget;

// Return Construct(target, args, newTarget).
return FunctionObject::construct(state, m_boundTargetFunction, mergedArgc, mergedArgv, newConstructTarget);
return Object::construct(state, m_boundTargetFunction, mergedArgc, mergedArgv, newConstructTarget);
}
}
7 changes: 3 additions & 4 deletions src/runtime/BoundFunctionObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ class BoundFunctionObject : public Object {
return Value(m_boundTargetFunction).isConstructor();
}

virtual Value call(ExecutionState& state, const Value& thisValue, const size_t calledArgc, Value* calledArgv) override;

virtual Object* construct(ExecutionState& state, const size_t calledArgc, Value* calledArgv, const Value& newTarget) override;

Value targetFunction()
{
return m_boundTargetFunction;
Expand All @@ -62,6 +58,9 @@ class BoundFunctionObject : public Object {
}

private:
virtual Value call(ExecutionState& state, const Value& thisValue, const size_t calledArgc, Value* calledArgv) override;
virtual Object* construct(ExecutionState& state, const size_t calledArgc, Value* calledArgv, const Value& newTarget) override;

SmallValue m_boundTargetFunction;
SmallValue m_boundThis;
SmallValueVector m_boundArguments;
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/FunctionObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ Value FunctionObject::processCall(ExecutionState& state, const Value& receiverSr
}

if (UNLIKELY(isSuperCall == true && isBuiltin() == true && isNewExpression == false)) {
Value returnValue = FunctionObject::construct(state, this, argc, argv);
Value returnValue = Object::construct(state, this, argc, argv);
returnValue.asObject()->setPrototype(state, receiverSrc.toObject(state)->getPrototype(state));
return returnValue;
}
Expand Down
44 changes: 10 additions & 34 deletions src/runtime/FunctionObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,40 +163,6 @@ class FunctionObject : public Object {
return FunctionKind::Normal;
}

// https://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
virtual Value call(ExecutionState& state, const Value& thisValue, const size_t argc, NULLABLE Value* argv) override
{
return processCall(state, thisValue, argc, argv, false);
}

virtual Object* construct(ExecutionState& state, const size_t argc, NULLABLE Value* argv, const Value& newTarget) override;

// https://www.ecma-international.org/ecma-262/6.0/#sec-call
ALWAYS_INLINE static Value call(ExecutionState& state, const Value& callee, const Value& thisValue, const size_t argc, NULLABLE Value* argv)
{
// If IsCallable(F) is false, throw a TypeError exception.
if (callee.isCallable() == false) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, errorMessage_NOT_Callable);
}
// Return F.[[Call]](V, argumentsList).
return callee.asObject()->call(state, thisValue, argc, argv);
}

// https://www.ecma-international.org/ecma-262/6.0/#sec-construct
ALWAYS_INLINE static Object* construct(ExecutionState& state, const Value& constructor, const size_t argc, NULLABLE Value* argv, Value newTarget = Value(Value::EmptyValue))
{
// If newTarget was not passed, let newTarget be F.
if (newTarget.isEmpty() == true) {
newTarget = constructor;
}
// Assert: IsConstructor (F) is true.
ASSERT(constructor.isConstructor() == true);
// Assert: IsConstructor (newTarget) is true.
ASSERT(newTarget.isConstructor() == true);
// Return F.[[Construct]](argumentsList, newTarget).
return constructor.asObject()->construct(state, argc, argv, newTarget);
}

// http://www.ecma-international.org/ecma-262/5.1/#sec-8.6.2
virtual const char* internalClassProperty() override
{
Expand All @@ -209,6 +175,16 @@ class FunctionObject : public Object {
}

private:
friend class Object;
friend class ObjectGetResult;
// https://www.ecma-international.org/ecma-262/6.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist
virtual Value call(ExecutionState& state, const Value& thisValue, const size_t argc, NULLABLE Value* argv) override
{
return processCall(state, thisValue, argc, argv, false);
}

virtual Object* construct(ExecutionState& state, const size_t argc, NULLABLE Value* argv, const Value& newTarget) override;

LexicalEnvironment* outerEnvironment()
{
return m_outerEnvironment;
Expand Down
8 changes: 4 additions & 4 deletions src/runtime/GlobalObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -885,11 +885,11 @@ static Value builtinDefineGetter(ExecutionState& state, Value thisValue, size_t
// Let O be ? ToObject(this value).
Object* O = thisValue.toObject(state);
// If IsCallable(getter) is false, throw a TypeError exception.
if (!argv[1].isFunction()) {
if (!argv[1].isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, String::emptyString, true, state.context()->staticStrings().__defineGetter__.string(), errorMessage_GlobalObject_CallbackNotCallable);
}
// Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true, [[Configurable]]: true}.
ObjectPropertyDescriptor desc(JSGetterSetter(argv[1].asFunction(), Value(Value::EmptyValue)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::EnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent));
ObjectPropertyDescriptor desc(JSGetterSetter(argv[1].asObject(), Value(Value::EmptyValue)), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::EnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent));

// Let key be ? ToPropertyKey(P).
ObjectPropertyName key(state, argv[0]);
Expand All @@ -910,11 +910,11 @@ static Value builtinDefineSetter(ExecutionState& state, Value thisValue, size_t
// Let O be ? ToObject(this value).
Object* O = thisValue.toObject(state);
// If IsCallable(getter) is false, throw a TypeError exception.
if (!argv[1].isFunction()) {
if (!argv[1].isCallable()) {
ErrorObject::throwBuiltinError(state, ErrorObject::TypeError, String::emptyString, true, state.context()->staticStrings().__defineSetter__.string(), errorMessage_GlobalObject_CallbackNotCallable);
}
// Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true, [[Configurable]]: true}.
ObjectPropertyDescriptor desc(JSGetterSetter(Value(Value::EmptyValue), argv[1].asFunction()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::EnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent));
ObjectPropertyDescriptor desc(JSGetterSetter(Value(Value::EmptyValue), argv[1].asObject()), (ObjectPropertyDescriptor::PresentAttribute)(ObjectPropertyDescriptor::EnumerablePresent | ObjectPropertyDescriptor::ConfigurablePresent));

// Let key be ? ToPropertyKey(P).
ObjectPropertyName key(state, argv[0]);
Expand Down
Loading