blob: 5d08029b9805028ec15378dc6efc22a3a29c9ad3 [file] [log] [blame]
// Copyright 2017 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/script/mozjs/util/algorithm_helpers.h"
#include "base/logging.h"
#include "cobalt/script/mozjs/mozjs_exception_state.h"
#include "third_party/mozjs/js/src/jsapi.h"
#include "third_party/mozjs/js/src/jsarray.h"
#include "third_party/mozjs/js/src/jsiter.h"
namespace cobalt {
namespace script {
namespace mozjs {
namespace util {
bool IsSameGcThing(JSContext* context, JS::HandleValue value1,
JS::HandleValue value2) {
if (value1.isNullOrUndefined()) {
return value2.isNullOrUndefined();
}
if (!value1.isGCThing() || !value2.isGCThing()) {
return false;
}
return value1.toGCThing() == value2.toGCThing();
}
bool GetIterator(JSContext* context, JS::HandleObject object,
JS::MutableHandleObject out_iterator) {
// Uses the jsiter API to get the iterator, as SM24 it doesn't seem to
// implement Array[@@iterator] yet.
JS::RootedValue iterator_value(context);
if (!js::GetIterator(context, object, JSITER_FOR_OF, &iterator_value)) {
return false;
}
JS::RootedObject iterator_object(context);
if (!iterator_value.isObject() ||
!JS_ValueToObject(context, iterator_value, iterator_object.address())) {
MozjsExceptionState exception(context);
exception.SetSimpleException(kNotObjectType);
return false;
}
out_iterator.set(iterator_object);
return true;
}
bool IteratorNext(JSContext* context, JS::HandleObject iterator,
JS::MutableHandleObject out_iterator_result) {
// IMPORTANT NOTE! If there is More, we cannot enter another script without
// calling Next to clear the result, or the interpreter will assert.
JS::RootedValue more(context);
if (!js_IteratorMore(context, iterator, &more)) {
MozjsExceptionState exception(context);
exception.SetSimpleException(kNotIterableType);
return false;
}
JS::RootedObject result(context, JS_NewObject(context, NULL, NULL, NULL));
JS::RootedValue done(context);
done.setBoolean(!JS::ToBoolean(more));
JS_SetProperty(context, result, "done", done.address());
if (JS::ToBoolean(done)) {
out_iterator_result.set(result);
return true;
}
JS::RootedValue value(context);
if (!js_IteratorNext(context, iterator, &value)) {
MozjsExceptionState exception(context);
exception.SetSimpleException(kNotIterableType);
return false;
}
JS_SetProperty(context, result, "value", value.address());
out_iterator_result.set(result);
return true;
}
bool IteratorComplete(JSContext* context, JS::HandleObject iterator_result) {
JS::RootedValue done(context);
if (!JS_GetProperty(context, iterator_result, "done", done.address())) {
return false;
}
return JS::ToBoolean(done);
}
bool IteratorValue(JSContext* context, JS::HandleObject iterator_result,
JS::MutableHandleValue out_result) {
JS::RootedValue value(context);
if (!JS_GetProperty(context, iterator_result, "value", value.address())) {
return false;
}
out_result.set(value);
return true;
}
bool IteratorStep(JSContext* context, JS::HandleObject iterator,
JS::MutableHandleObject out_iterator_result) {
JS::RootedObject result(context);
if (!IteratorNext(context, iterator, &result)) {
return false;
}
if (IteratorComplete(context, result)) {
return false;
}
out_iterator_result.set(result);
return true;
}
bool IteratorClose(JSContext* context, JS::HandleObject iterator) {
return js::CloseIterator(context, iterator);
}
bool Call0(JSContext* context, JS::HandleFunction function,
JS::HandleObject value, JS::MutableHandleValue out_result) {
const size_t kNumArguments = 0;
JS::Value *args = NULL;
js::SetValueRangeToNull(args, kNumArguments);
js::AutoValueArray auto_array_rooter(context, args, kNumArguments);
return JS::Call(context, value, function, kNumArguments, args,
out_result.address());
}
bool Invoke0(JSContext* context, JS::HandleObject value,
const char* property_name, JS::MutableHandleValue out_result) {
JS::RootedValue property(context);
if (!JS_GetProperty(context, value, property_name, property.address())) {
return false;
}
if (!property.isObject() ||
!JS_ObjectIsCallable(context, JSVAL_TO_OBJECT(property))) {
return false;
}
JS::RootedFunction function(context, JS_ValueToFunction(context, property));
DCHECK(function);
return util::Call0(context, function, value, out_result);
}
} // namespace util
} // namespace mozjs
} // namespace script
} // namespace cobalt