Bug 578700 - Binary Data: initialize architecture. r=nmatsakis

--HG--
extra : amend_source : 7775dc457c0c25283608e583472dc7cf04bffe8c
This commit is contained in:
Nikhil Marathe 2013-07-25 17:57:04 -07:00
parent b023ffcb98
commit 88f8ec69ce
10 changed files with 427 additions and 0 deletions

View File

@ -72,6 +72,10 @@ ifdef NIGHTLY_BUILD
DEFINES += -DENABLE_PARALLEL_JS
endif
ifdef NIGHTLY_BUILD
DEFINES += -DENABLE_BINARYDATA
endif
# Ion
ifdef ENABLE_ION
VPATH += $(srcdir)/ion

View File

@ -0,0 +1,201 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "builtin/BinaryData.h"
#include "jscompartment.h"
#include "jsobj.h"
#include "jsatominlines.h"
#include "jsobjinlines.h"
#include "vm/GlobalObject.h"
using namespace js;
JSBool TypeThrowError(JSContext *cx, unsigned argc, Value *vp)
{
return ReportIsNotFunction(cx, *vp);
}
JSBool DataThrowError(JSContext *cx, unsigned argc, Value *vp)
{
return ReportIsNotFunction(cx, *vp);
}
// FIXME will actually require knowing function name
JSBool createNumericBlock(JSContext *cx, unsigned argc, jsval *vp)
{
return false;
}
JSBool createArrayType(JSContext *cx, unsigned argc, jsval *vp)
{
return false;
}
JSBool createStructType(JSContext *cx, unsigned argc, jsval *vp)
{
return false;
}
JSBool DataInstanceUpdate(JSContext *cx, unsigned argc, jsval *vp)
{
return false;
}
JSBool
ArrayTypeObject::repeat(JSContext *cx, unsigned int argc, jsval *vp)
{
return false;
}
bool
GlobalObject::initDataObject(JSContext *cx, Handle<GlobalObject *> global)
{
RootedObject DataProto(cx);
DataProto = NewObjectWithGivenProto(cx, &DataClass, global->getOrCreateObjectPrototype(cx), global, SingletonObject);
if (!DataProto)
return false;
RootedAtom DataName(cx, ClassName(JSProto_Data, cx));
RootedFunction DataCtor(cx, global->createConstructor(cx, DataThrowError, DataName, 1, JSFunction::ExtendedFinalizeKind));
if (!DataCtor)
return false;
if (!JS_DefineFunction(cx, DataProto, "update", DataInstanceUpdate, 1, 0))
return false;
if (!LinkConstructorAndPrototype(cx, DataCtor, DataProto))
return false;
if (!DefineConstructorAndPrototype(cx, global, JSProto_Data, DataCtor, DataProto))
return false;
global->setReservedSlot(JSProto_Data, ObjectValue(*DataCtor));
return true;
}
bool
GlobalObject::initTypeObject(JSContext *cx, Handle<GlobalObject *> global)
{
RootedObject TypeProto(cx, global->getOrCreateDataObject(cx));
if (!TypeProto)
return false;
RootedAtom TypeName(cx, ClassName(JSProto_Type, cx));
RootedFunction TypeCtor(cx, global->createConstructor(cx, TypeThrowError, TypeName, 1, JSFunction::ExtendedFinalizeKind));
if (!TypeCtor)
return false;
if (!LinkConstructorAndPrototype(cx, TypeCtor, TypeProto))
return false;
if (!DefineConstructorAndPrototype(cx, global, JSProto_Type, TypeCtor, TypeProto))
return false;
global->setReservedSlot(JSProto_Type, ObjectValue(*TypeCtor));
return true;
}
static JSObject *
SetupComplexHeirarchy(JSContext *cx, Handle<GlobalObject *> global, HandleObject complexObject)
{
// get the 'Type' constructor
RootedObject TypeObject(cx, global->getOrCreateTypeObject(cx));
if (!TypeObject)
return NULL;
// Set complexObject.__proto__ = Type
if (!JS_SetPrototype(cx, complexObject, TypeObject))
return NULL;
RootedObject DataObject(cx, global->getOrCreateDataObject(cx));
if (!DataObject)
return NULL;
RootedValue DataProtoVal(cx);
if (!JSObject::getProperty(cx, DataObject, DataObject, cx->names().classPrototype, &DataProtoVal))
return NULL;
RootedObject DataProto(cx, DataProtoVal.toObjectOrNull());
if (!DataProto)
return NULL;
// Set complexObject.prototype.__proto__ = Data
RootedObject prototypeObj(cx, JS_NewObject(cx, NULL, NULL, global));
if (!LinkConstructorAndPrototype(cx, complexObject, prototypeObj))
return NULL;
if (!JS_SetPrototype(cx, prototypeObj, DataObject))
return NULL;
// Set complexObject.prototype.prototype.__proto__ = Data.prototype
// TODO does this have to actually be a Class so we can set accessor properties etc?
RootedObject prototypePrototypeObj(cx, JS_NewObject(cx, NULL, NULL, global));
if (!LinkConstructorAndPrototype(cx, prototypeObj, prototypePrototypeObj))
return NULL;
if (!JS_SetPrototype(cx, prototypePrototypeObj, DataProto))
return NULL;
return complexObject;
}
static JSObject *
InitComplexClasses(JSContext *cx, Handle<GlobalObject *> global)
{
// TODO FIXME use DefineConstructorAndPrototype and other
// utilities
RootedFunction ArrayTypeFun(cx, JS_DefineFunction(cx, global, "ArrayType", createArrayType, 1, 0));
if (!ArrayTypeFun)
return NULL;
if (!SetupComplexHeirarchy(cx, global, ArrayTypeFun))
return NULL;
// ArrayType.prototype.repeat
RootedValue ArrayTypePrototypeVal(cx);
if (!JSObject::getProperty(cx, ArrayTypeFun, ArrayTypeFun, cx->names().classPrototype, &ArrayTypePrototypeVal))
return NULL;
if (!JS_DefineFunction(cx, ArrayTypePrototypeVal.toObjectOrNull(), "repeat", ArrayTypeObject::repeat, 1, 0))
return NULL;
RootedFunction StructTypeFun(cx, JS_DefineFunction(cx, global, "StructType", createStructType, 1, 0));
if (!StructTypeFun)
return NULL;
if (!SetupComplexHeirarchy(cx, global, StructTypeFun))
return NULL;
return global;
}
JSObject *
js_InitBinaryDataClasses(JSContext *cx, HandleObject obj)
{
JS_ASSERT(obj->is<GlobalObject>());
Rooted<GlobalObject *> global(cx, &obj->as<GlobalObject>());
typedef float_t float32_t;
typedef double_t float64_t;
#define BINARYDATA_NUMERIC_DEFINE(type_)\
do {\
JSFunction *numFun = JS_DefineFunction(cx, obj, #type_, createNumericBlock, 1, 0);\
if (!numFun)\
return NULL;\
\
if (!JS_DefineProperty(cx, numFun, "bytes", INT_TO_JSVAL(sizeof(type_##_t)), JS_PropertyStub, JS_StrictPropertyStub, 0))\
return NULL;\
} while(0);
BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_DEFINE)
#undef BINARYDATA_NUMERIC_DEFINE
if (!InitComplexClasses(cx, global))
return NULL;
return global;
}

103
js/src/builtin/BinaryData.h Normal file
View File

@ -0,0 +1,103 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef builtin_BinaryData_h
#define builtin_BinaryData_h
#include "jsapi.h"
#include "jsobj.h"
#include "jsfriendapi.h"
#include "gc/Heap.h"
namespace js {
class Block : public gc::Cell
{
};
static Class DataClass = {
"Data",
JSCLASS_HAS_CACHED_PROTO(JSProto_Data),
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub
};
static Class TypeClass = {
"Type",
JSCLASS_HAS_CACHED_PROTO(JSProto_Type),
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub
};
#define BINARYDATA_FOR_EACH_NUMERIC_TYPES(macro_)\
macro_(uint8)\
macro_(uint16)\
macro_(uint32)\
macro_(uint64)\
macro_(int8)\
macro_(int16)\
macro_(int32)\
macro_(int64)\
macro_(float32)\
macro_(float64)
#define BINARYDATA_NUMERIC_CLASSES(type_)\
static Class type_##BlockClass = {\
#type_,\
JSCLASS_HAS_CACHED_PROTO(JSProto_##type_),\
JS_PropertyStub, /* addProperty */\
JS_DeletePropertyStub, /* delProperty */\
JS_PropertyStub, /* getProperty */\
JS_StrictPropertyStub, /* setProperty */\
JS_EnumerateStub,\
JS_ResolveStub,\
JS_ConvertStub\
};
BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_CLASSES)
static Class ArrayTypeClass = {
"ArrayType",
JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayType),
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub
};
static Class StructTypeClass = {
"StructType",
JSCLASS_HAS_CACHED_PROTO(JSProto_StructType),
JS_PropertyStub,
JS_DeletePropertyStub,
JS_PropertyStub,
JS_StrictPropertyStub,
JS_EnumerateStub,
JS_ResolveStub,
JS_ConvertStub
};
class ArrayTypeObject : public JSObject
{
public:
static JSBool repeat(JSContext *cx, unsigned int argc, jsval *vp);
};
}
#endif /* builtin_BinaryData_h */

View File

@ -177,6 +177,14 @@ GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp)
if (!JS_SetProperty(cx, info, "parallelJS", &value))
return false;
#ifdef ENABLE_BINARYDATA
value = BooleanValue(true);
#else
value = BooleanValue(false);
#endif
if (!JS_SetProperty(cx, info, "binary-data", &value))
return false;
*vp = ObjectValue(*info);
return true;
}

View File

@ -53,6 +53,7 @@
#if ENABLE_YARR_JIT
#include "assembler/jit/ExecutableAllocator.h"
#endif
#include "builtin/BinaryData.h"
#include "builtin/Eval.h"
#include "builtin/Intl.h"
#include "builtin/MapObject.h"
@ -1849,6 +1850,9 @@ static const JSStdName standard_class_atoms[] = {
{js_InitProxyClass, EAGER_CLASS_ATOM(Proxy), OCLASP(ObjectProxy)},
#if ENABLE_INTL_API
{js_InitIntlClass, EAGER_ATOM_AND_CLASP(Intl)},
#endif
#ifdef ENABLE_BINARYDATA
{js_InitBinaryDataClasses, EAGER_ATOM_AND_CLASP(Type)},
#endif
{NULL, 0, NULL}
};
@ -1906,6 +1910,17 @@ static const JSStdName standard_class_names[] = {
TYPED_ARRAY_CLASP(TYPE_UINT8_CLAMPED)},
{js_InitTypedArrayClasses, EAGER_CLASS_ATOM(DataView), &DataViewObject::class_},
/* Binary Data */
#ifdef ENABLE_BINARYDATA
{js_InitBinaryDataClasses, EAGER_ATOM_AND_CLASP(Type)},
{js_InitBinaryDataClasses, EAGER_ATOM_AND_CLASP(Data)},
#define BINARYDATA_NUMERIC_NAMES(type_)\
{js_InitBinaryDataClasses, EAGER_CLASS_ATOM(type_), CLASP(type_##Block)},
BINARYDATA_FOR_EACH_NUMERIC_TYPES(BINARYDATA_NUMERIC_NAMES)
#undef BINARYDATA_NUMERIC_NAMES
{js_InitBinaryDataClasses, EAGER_ATOM_AND_CLASP(ArrayType)},
{js_InitBinaryDataClasses, EAGER_ATOM_AND_CLASP(StructType)},
#endif
{NULL, 0, NULL}
};

View File

@ -56,5 +56,19 @@
macro(DataView, 35, js_InitTypedArrayClasses) \
macro(ParallelArray, 36, js_InitParallelArrayClass) \
macro(Intl, 37, js_InitIntlClass) \
macro(Type, 38, js_InitBinaryDataClasses) \
macro(Data, 39, js_InitBinaryDataClasses) \
macro(uint8, 40, js_InitBinaryDataClasses) \
macro(uint16, 41, js_InitBinaryDataClasses) \
macro(uint32, 42, js_InitBinaryDataClasses) \
macro(uint64, 43, js_InitBinaryDataClasses) \
macro(int8, 44, js_InitBinaryDataClasses) \
macro(int16, 45, js_InitBinaryDataClasses) \
macro(int32, 46, js_InitBinaryDataClasses) \
macro(int64, 47, js_InitBinaryDataClasses) \
macro(float32, 48, js_InitBinaryDataClasses) \
macro(float64, 49, js_InitBinaryDataClasses) \
macro(ArrayType, 50, js_InitBinaryDataClasses) \
macro(StructType, 51, js_InitBinaryDataClasses) \
#endif /* jsprototypes_h */

View File

@ -80,6 +80,7 @@ EXPORTS.js += [
CPP_SOURCES += [
'ArgumentsObject.cpp',
'BinaryData.cpp',
'BytecodeCompiler.cpp',
'BytecodeEmitter.cpp',
'CharacterEncoding.cpp',

View File

@ -0,0 +1,66 @@
// |reftest| skip-if(!this.hasOwnProperty("Type"))
var BUGNUMBER = 578700;
var summary = 'Binary Data class diagram';
function assertNotEq(a, b) {
var ok = false;
try {
assertEq(a, b);
} catch(exc) {
ok = true;
}
if (!ok)
throw new TypeError("Assertion failed: assertNotEq(" + a + " " + b + ")");
}
function runTests() {
print(BUGNUMBER + ": " + summary);
assertEq(Data.__proto__, Function.prototype);
assertEq(Data.prototype.__proto__, Object.prototype);
assertEq(Data.prototype.constructor, Data);
assertEq(typeof Data.prototype.update === "function", true);
assertEq(Type.__proto__, Function.prototype);
assertEq(Type.prototype, Data);
var sizes = [1, 2, 4, 8, 1, 2, 4, 8, 4, 8];
[ uint8, uint16, uint32,
uint64, int8, int16,
int32, int64, float32, float64 ].forEach(function(numType, i) {
assertEq(numType.__proto__, Function.prototype);
assertEq(numType.bytes, sizes[i]);
});
assertEq(ArrayType.__proto__, Type);
assertEq(ArrayType.prototype.__proto__, Type.prototype);
assertEq(typeof ArrayType.prototype.repeat === "function", true);
assertEq(ArrayType.prototype.prototype.__proto__, Data.prototype);
assertEq(StructType.__proto__, Type);
assertEq(StructType.prototype.__proto__, Type.prototype);
assertEq(StructType.prototype.prototype.__proto__, Data.prototype);
// Change global 'Type' and see if things stay sane.
Type = function() {
return 42;
}
Data = function() {
return 43;
}
assertNotEq(ArrayType.prototype.__proto__, Type.prototype);
assertNotEq(ArrayType.prototype.prototype.__proto__, Data.prototype);
assertNotEq(StructType.prototype.__proto__, Type.prototype);
assertNotEq(StructType.prototype.prototype.__proto__, Data.prototype);
if (typeof reportCompare === "function")
reportCompare(true, true);
print("Tests complete");
}
runTests();

View File

View File

@ -27,6 +27,9 @@ js_InitFunctionClass(JSContext *cx, js::HandleObject obj);
extern JSObject *
js_InitTypedArrayClasses(JSContext *cx, js::HandleObject obj);
extern JSObject *
js_InitBinaryDataClasses(JSContext *cx, js::HandleObject obj);
namespace js {
class Debugger;
@ -327,6 +330,14 @@ class GlobalObject : public JSObject
return &getPrototype(JSProto_Iterator).toObject();
}
JSObject *getOrCreateDataObject(JSContext *cx) {
return getOrCreateObject(cx, JSProto_Data, initDataObject);
}
JSObject *getOrCreateTypeObject(JSContext *cx) {
return getOrCreateObject(cx, JSProto_Type, initTypeObject);
}
private:
typedef bool (*ObjectInitOp)(JSContext *cx, Handle<GlobalObject*> global);
@ -429,6 +440,10 @@ class GlobalObject : public JSObject
static bool initNumberFormatProto(JSContext *cx, Handle<GlobalObject*> global);
static bool initDateTimeFormatProto(JSContext *cx, Handle<GlobalObject*> global);
// Implemented in builtin/BinaryData.cpp
static bool initTypeObject(JSContext *cx, Handle<GlobalObject*> global);
static bool initDataObject(JSContext *cx, Handle<GlobalObject*> global);
static bool initStandardClasses(JSContext *cx, Handle<GlobalObject*> global);
typedef js::Vector<js::Debugger *, 0, js::SystemAllocPolicy> DebuggerVector;