# HG changeset patch # Parent 3b955f306226bfe7f8f4035a8573bcf8e2fb0dcc # User Nikhil Marathe Bug 578700 - Binary Data initialize architecture. diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -20,16 +20,17 @@ #include #include #include "jstypes.h" #include "jsutil.h" #include "jsprf.h" #include "jsarray.h" #include "jsatom.h" +#include "jsbinarydata.h" #include "jsbool.h" #include "jsclone.h" #include "jscntxt.h" #include "jsdate.h" #include "jsdtoa.h" #include "jsexn.h" #include "jsfun.h" #include "jsgc.h" @@ -1821,16 +1822,24 @@ static const JSStdName standard_class_at {js_InitSetClass, EAGER_ATOM_AND_OCLASP(Set)}, #ifdef ENABLE_PARALLEL_JS {js_InitParallelArrayClass, EAGER_ATOM_AND_OCLASP(ParallelArray)}, #endif {js_InitProxyClass, EAGER_ATOM_AND_CLASP(Proxy)}, #if ENABLE_INTL_API {js_InitIntlClass, EAGER_ATOM_AND_CLASP(Intl)}, #endif + {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)}, {NULL, 0, NULL} }; /* * Table of top-level function and constant names and their init functions. * If you add a "standard" global function or property, remember to update * this table. */ diff --git a/js/src/jsbinarydata.cpp b/js/src/jsbinarydata.cpp new file mode 100644 --- /dev/null +++ b/js/src/jsbinarydata.cpp @@ -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 "jsbinarydata.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 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 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 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 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()); + Rooted global(cx, &obj->as()); + +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; +} diff --git a/js/src/jsbinarydata.h b/js/src/jsbinarydata.h new file mode 100644 --- /dev/null +++ b/js/src/jsbinarydata.h @@ -0,0 +1,106 @@ +/* -*- 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 jsbinarydata_h +#define jsbinarydata_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); +}; +} + +extern JS_FRIEND_API(JSObject *) +js_InitBinaryDataClasses(JSContext *cx, js::HandleObject obj); + +#endif /* jsbinarydata_h */ diff --git a/js/src/jsprototypes.h b/js/src/jsprototypes.h --- a/js/src/jsprototypes.h +++ b/js/src/jsprototypes.h @@ -51,10 +51,24 @@ macro(Uint8ClampedArray, 30, js_InitTypedArrayClasses) \ macro(Proxy, 31, js_InitProxyClass) \ macro(WeakMap, 32, js_InitWeakMapClass) \ macro(Map, 33, js_InitMapClass) \ macro(Set, 34, js_InitSetClass) \ 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 */ diff --git a/js/src/moz.build b/js/src/moz.build --- a/js/src/moz.build +++ b/js/src/moz.build @@ -136,16 +136,17 @@ CPP_SOURCES += [ 'YarrPattern.cpp', 'YarrSyntaxChecker.cpp', 'Zone.cpp', 'jsalloc.cpp', 'jsanalyze.cpp', 'jsapi.cpp', 'jsarray.cpp', 'jsatom.cpp', + 'jsbinarydata.cpp', 'jsbool.cpp', 'jsclone.cpp', 'jscntxt.cpp', 'jscompartment.cpp', 'jscrashreport.cpp', 'jsdate.cpp', 'jsdbgapi.cpp', 'jsdtoa.cpp', diff --git a/js/src/tests/ecma_6/BinaryData/architecture.js b/js/src/tests/ecma_6/BinaryData/architecture.js new file mode 100644 --- /dev/null +++ b/js/src/tests/ecma_6/BinaryData/architecture.js @@ -0,0 +1,59 @@ +var BUGNUMBER = 578700; +var summary = 'Test class diagram'; + +print(BUGNUMBER + ": " + summary); + +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 + ")"); +} + +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"); diff --git a/js/src/tests/ecma_6/BinaryData/shell.js b/js/src/tests/ecma_6/BinaryData/shell.js new file mode 100644 diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -22,16 +22,19 @@ extern JSObject * js_InitObjectClass(JSContext *cx, js::HandleObject obj); extern JSObject * 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; /* * Global object slots are reserved as follows: * * [0, JSProto_LIMIT) @@ -322,16 +325,24 @@ class GlobalObject : public JSObject JSObject *getOrCreateDateTimeFormatPrototype(JSContext *cx) { return getOrCreateObject(cx, DATE_TIME_FORMAT_PROTO, initDateTimeFormatProto); } JSObject *getIteratorPrototype() { 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 global); JSObject *getOrCreateObject(JSContext *cx, unsigned slot, ObjectInitOp init) { Value v = getSlotRef(slot); if (v.isObject()) return &v.toObject(); Rooted self(cx, this); @@ -424,16 +435,20 @@ class GlobalObject : public JSObject static bool initSetIteratorProto(JSContext *cx, Handle global); // Implemented in Intl.cpp. static bool initIntlObject(JSContext *cx, Handle global); static bool initCollatorProto(JSContext *cx, Handle global); static bool initNumberFormatProto(JSContext *cx, Handle global); static bool initDateTimeFormatProto(JSContext *cx, Handle global); + // Implemented in jsbinarydata.cpp + static bool initTypeObject(JSContext *cx, Handle global); + static bool initDataObject(JSContext *cx, Handle global); + static bool initStandardClasses(JSContext *cx, Handle global); typedef js::Vector DebuggerVector; /* * The collection of Debugger objects debugging this global. If this global * is not a debuggee, this returns either NULL or an empty vector. */