diff -r 6b3ac7e864ba binaries/data/mods/_test.sim/simulation/components/test-entityid.js
--- a/binaries/data/mods/_test.sim/simulation/components/test-entityid.js	Wed Nov 03 17:52:07 2010 +0000
+++ b/binaries/data/mods/_test.sim/simulation/components/test-entityid.js	Thu Nov 04 14:52:01 2010 +0000
@@ -2,8 +2,14 @@
 
 TestScript1A.prototype.GetX = function() {
 	// Test that .entity is readonly
-	delete this.entity;
-	this.entity = -1;
+	try {
+		delete this.entity;
+		Engine.TS_FAIL("Missed exception");
+	} catch (e) { }
+	try {
+		this.entity = -1;
+		Engine.TS_FAIL("Missed exception");
+	} catch (e) { }
 	
 	// and return the value
 	return this.entity;
diff -r 6b3ac7e864ba binaries/data/mods/_test.sim/simulation/components/test-serialize.js
--- a/binaries/data/mods/_test.sim/simulation/components/test-serialize.js	Wed Nov 03 17:52:07 2010 +0000
+++ b/binaries/data/mods/_test.sim/simulation/components/test-serialize.js	Thu Nov 04 14:52:01 2010 +0000
@@ -19,8 +19,14 @@
 
 TestScript1_entity.prototype.GetX = function() {
 	// Test that .entity is readonly
-	delete this.entity;
-	this.entity = -1;
+	try {
+		delete this.entity;
+		Engine.TS_FAIL("Missed exception");
+	} catch (e) { }
+	try {
+		this.entity = -1;
+		Engine.TS_FAIL("Missed exception");
+	} catch (e) { }
 
 	// and return the value
 	return this.entity;
diff -r 6b3ac7e864ba source/graphics/scripting/JSInterface_Camera.cpp
--- a/source/graphics/scripting/JSInterface_Camera.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,310 +0,0 @@
-/* Copyright (C) 2009 Wildfire Games.
- * This file is part of 0 A.D.
- *
- * 0 A.D. is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * 0 A.D. 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "precompiled.h"
-
-#include "JSInterface_Camera.h"
-
-#include "scripting/JSConversions.h"
-#include "maths/scripting/JSInterface_Vector3D.h"
-#include "graphics/Camera.h"
-#include "maths/Vector3D.h"
-#include "maths/Matrix3D.h"
-#include "maths/MathUtil.h"
-#include "graphics/Terrain.h"
-#include "ps/Game.h"
-#include "graphics/GameView.h"
-
-
-JSClass JSI_Camera::JSI_class = {
-	"Camera", JSCLASS_HAS_PRIVATE,
-	JS_PropertyStub, JS_PropertyStub,
-	JSI_Camera::getProperty, JSI_Camera::setProperty,
-	JS_EnumerateStub, JS_ResolveStub,
-	JS_ConvertStub, JSI_Camera::finalize,
-	NULL, NULL, NULL, NULL
-};
-
-JSPropertySpec JSI_Camera::JSI_props[] =
-{
-	{ "position", JSI_Camera::vector_position, JSPROP_ENUMERATE },
-	{ "orientation", JSI_Camera::vector_orientation, JSPROP_ENUMERATE },
-	{ "up", JSI_Camera::vector_up, JSPROP_ENUMERATE },
-	{ 0 },
-};
-
-JSFunctionSpec JSI_Camera::JSI_methods[] = 
-{
-    { "lookAt", JSI_Camera::lookAt, 2, 0, 0 },
-	{ "getFocus", JSI_Camera::getFocus, 0, 0, 0 },
-	{ 0 }
-};
-
-void JSI_Camera::init()
-{
-	g_ScriptingHost.DefineCustomObjectType( &JSI_class, JSI_Camera::construct, 0, JSI_props, JSI_methods, NULL, NULL );
-}
-
-JSI_Camera::Camera_Info::Camera_Info()
-{
-	Initialise();
-}
-
-JSI_Camera::Camera_Info::Camera_Info( const CVector3D& Position )
-{
-	CMatrix3D Orient;
-	Orient.SetXRotation( DEGTORAD( 30 ) );
-	Orient.RotateY( DEGTORAD( -45 ) );
-	Orient.Translate( Position );
-
-	Initialise( (const CMatrix3D&)Orient );
-}
-
-JSI_Camera::Camera_Info::Camera_Info( const CVector3D& Position, const CVector3D& Orientation )
-{
-	Initialise();
-	m_Data->LookAlong( Position, Orientation, CVector3D( 0.0f, 1.0f, 0.0f ) );
-}
-
-JSI_Camera::Camera_Info::Camera_Info( const CVector3D& Position, const CVector3D& Orientation, const CVector3D& Up )
-{
-	Initialise();
-	m_Data->LookAlong( Position, Orientation, Up );
-}
-
-JSI_Camera::Camera_Info::Camera_Info( const CMatrix3D& Orientation )
-{
-	Initialise( Orientation );
-}
-
-JSI_Camera::Camera_Info::Camera_Info( CCamera* Reference )
-{
-	m_Data = Reference;
-	m_EngineOwned = true;
-}
-
-JSI_Camera::Camera_Info::~Camera_Info()
-{
-	if( !m_EngineOwned )
-		delete( m_Data );
-}
-
-void JSI_Camera::Camera_Info::Initialise()
-{
-	CMatrix3D Orient;
-	Orient.SetXRotation( DEGTORAD( 30 ) );
-	Orient.RotateY( DEGTORAD( -45 ) );
-	Orient.Translate( 100, 150, -100 );
-
-	Initialise( (const CMatrix3D&)Orient );
-}
-
-void JSI_Camera::Camera_Info::Initialise( const CMatrix3D& Orientation )
-{
-	m_Data = new CCamera();
-	m_EngineOwned = false;
-
-	m_Data->LookAlong( Orientation.GetTranslation(), Orientation.GetIn(), Orientation.GetUp() );
-}
-
-void JSI_Camera::Camera_Info::Freshen()
-{
-	m_sv_Position = m_Data->m_Orientation.GetTranslation();
-	m_sv_Orientation = m_Data->m_Orientation.GetIn();
-	m_sv_Up = m_Data->m_Orientation.GetUp();
-}
-
-void JSI_Camera::Camera_Info::Update()
-{
-	m_Data->LookAlong( m_sv_Position, m_sv_Orientation, m_sv_Up );
-}
-
-void JSI_Camera::Camera_Info::FreshenTarget()
-{
-	m_sv_Target = m_Data->GetFocus();
-}
-
-JSBool JSI_Camera::getCamera( JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
-{
-	if( g_Game && g_Game->GetView()->GetCamera() )
-	{
-		JSObject* camera = JS_NewObject( cx, &JSI_Camera::JSI_class, NULL, NULL );
-		JS_SetPrivate( cx, camera, new Camera_Info( g_Game->GetView()->GetCamera() ) );
-		*vp = OBJECT_TO_JSVAL( camera );
-	}
-	else
-	{
-		*vp = JSVAL_NULL;
-	}
-	return( JS_TRUE );
-}
-
-JSBool JSI_Camera::setCamera( JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
-{
-	JSObject* camera = JSVAL_TO_OBJECT( *vp );
-	Camera_Info* cameraInfo;
-	if( !JSVAL_IS_OBJECT( *vp ) || NULL == ( cameraInfo = (Camera_Info*)JS_GetInstancePrivate( cx, camera, &JSI_Camera::JSI_class, NULL ) ) )
-	{
-		JS_ReportError( cx, "[Camera] Invalid object" );
-	}
-	else
-	{
-		g_Game->GetView()->GetCamera()->m_Orientation = cameraInfo->m_Data->m_Orientation;
-	}
-	return( JS_TRUE );
-}
-
-JSBool JSI_Camera::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
-{
-	if( !JSVAL_IS_INT( id ) )
-		return( JS_TRUE );
-
-	Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
-	if( !cameraInfo )
-	{
-		JS_ReportError( cx, "[Camera] Invalid Reference" );
-		return( JS_TRUE );
-	}
-	
-	CVector3D* d;
-
-	switch( ToPrimitive<int>( id ) )
-	{
-	case vector_position: d = &cameraInfo->m_sv_Position; break;
-	case vector_orientation: d = &cameraInfo->m_sv_Orientation; break;
-	case vector_up: d = &cameraInfo->m_sv_Up; break;
-	default: return( JS_TRUE );
-	}
-
-	JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
-	JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( d, cameraInfo, ( void( IPropertyOwner::* )() )&Camera_Info::Update, ( void( IPropertyOwner::* )() )&Camera_Info::Freshen ) );
-	*vp = OBJECT_TO_JSVAL( vector3d );
-	return( JS_TRUE );
-}
-
-JSBool JSI_Camera::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
-{
-	if( !JSVAL_IS_INT( id ) )
-		return( JS_TRUE );
-
-	Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
-	if( !cameraInfo )
-	{
-		JS_ReportError( cx, "[Camera] Invalid reference" );
-		return( JS_TRUE );
-	}
-	
-	JSObject* vector3d = JSVAL_TO_OBJECT( *vp );
-	JSI_Vector3D::Vector3D_Info* v = NULL;
-
-	if( JSVAL_IS_OBJECT( *vp ) && NULL != ( v = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( g_ScriptingHost.getContext(), vector3d, &JSI_Vector3D::JSI_class, NULL ) ) )
-	{
-		cameraInfo->Freshen();
-
-		switch( ToPrimitive<int>( id ) )
-		{
-		case vector_position: cameraInfo->m_sv_Position = *( v->vector ); break;
-		case vector_orientation: cameraInfo->m_sv_Orientation = *( v->vector ); break;
-		case vector_up: cameraInfo->m_sv_Up = *( v->vector ); break;
-		}
-
-		cameraInfo->Update();
-	}
-
-	return( JS_TRUE );
-}
-
-#define GETVECTOR( jv ) ( ( JSVAL_IS_OBJECT( jv ) && NULL != ( v = (JSI_Vector3D::Vector3D_Info*)JS_GetInstancePrivate( g_ScriptingHost.getContext(), JSVAL_TO_OBJECT( jv ), &JSI_Vector3D::JSI_class, NULL ) ) ) ? *(v->vector) : CVector3D() )
-
-
-JSBool JSI_Camera::lookAt( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
-{
-	JSI_Vector3D::Vector3D_Info* v = NULL;
-	Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
-
-	JSU_REQUIRE_PARAM_RANGE(2, 3);
-
-	cameraInfo->m_sv_Position = GETVECTOR( argv[0] );
-	cameraInfo->m_sv_Orientation = GETVECTOR( argv[1] ) - cameraInfo->m_sv_Position;
-	cameraInfo->m_sv_Orientation.Normalize();
-
-	if( argc == 2 )
-	{
-		cameraInfo->m_sv_Up = CVector3D( 0.0f, 1.0f, 0.0f );
-	}
-	else if( argc == 3 )
-	{
-		cameraInfo->m_sv_Up = GETVECTOR( argv[2] );
-	}
-
-	cameraInfo->Update();
-
-	*rval = JSVAL_TRUE;
-	return( JS_TRUE );
-}
-
-JSBool JSI_Camera::getFocus( JSContext* cx, JSObject* obj,
-	uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
-{
-	// Largely copied from the equivalent method in CCamera
-
-	Camera_Info* cameraInfo = (Camera_Info*)JS_GetPrivate( cx, obj );
-
-	JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
-	JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( &( cameraInfo->m_sv_Target ), cameraInfo, NULL, ( void( IPropertyOwner::* )() )&Camera_Info::FreshenTarget ) );
-	*rval = OBJECT_TO_JSVAL( vector3d );
-	return( JS_TRUE );
-}
-
-JSBool JSI_Camera::construct( JSContext* cx, JSObject* UNUSED(obj),
-	uintN argc, jsval* argv, jsval* rval )
-{
-	JSI_Vector3D::Vector3D_Info* v = NULL;
-
-	JSObject* camera = JS_NewObject( cx, &JSI_Camera::JSI_class, NULL, NULL );
-
-	JSU_REQUIRE_MAX_PARAMS(3);
-	Camera_Info* camera_info = 0;
-	switch(argc)
-	{
-	case 0:
-		camera_info = new Camera_Info();
-		break;
-	case 1:
-		camera_info = new Camera_Info( GETVECTOR( argv[0] ) );
-		break;
-	case 2:
-		camera_info = new Camera_Info( GETVECTOR( argv[0] ), GETVECTOR( argv[1] ) );
-		break;
-	case 3:
-		camera_info = new Camera_Info( GETVECTOR( argv[0] ), GETVECTOR( argv[1] ), GETVECTOR( argv[2] ) );
-		break;
-	NODEFAULT;
-	}
-
-#undef GET_VECTOR
-
-	JS_SetPrivate( cx, camera, camera_info );
-	*rval = OBJECT_TO_JSVAL( camera );
-	return( JS_TRUE );
-}
-
-void JSI_Camera::finalize( JSContext* cx, JSObject* obj )
-{
-	delete( (Camera_Info*)JS_GetPrivate( cx, obj ) );
-}
-
diff -r 6b3ac7e864ba source/graphics/scripting/JSInterface_Camera.h
--- a/source/graphics/scripting/JSInterface_Camera.h	Wed Nov 03 17:52:07 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,101 +0,0 @@
-/* Copyright (C) 2009 Wildfire Games.
- * This file is part of 0 A.D.
- *
- * 0 A.D. is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * 0 A.D. 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-// JSInterface_Camera.h
-//
-// A JavaScript wrapper around a camera object.
-//
-// Usage: When manipulating objects of type 'Camera' in JavaScript
-
-#include "scripting/ScriptingHost.h"
-
-#include "maths/Vector3D.h"
-#include "graphics/Camera.h"
-#include "graphics/HFTracer.h"
-
-#ifndef INCLUDED_JSI_CAMERA
-#define INCLUDED_JSI_CAMERA
-
-namespace JSI_Camera
-{
-	enum
-	{
-		vector_position,
-		vector_orientation,
-		vector_up
-	};
-
-	enum
-	{
-		lookat
-	};
-
-	struct Camera_Info : public IPropertyOwner
-	{
-		CCamera* m_Data;
-		bool m_EngineOwned;
-		CVector3D m_sv_Position;
-		CVector3D m_sv_Orientation;
-		CVector3D m_sv_Up;
-		CVector3D m_sv_Target;
-
-		Camera_Info(); // Create a camera set to the initial view
-
-		Camera_Info( const CVector3D& Position );
-		Camera_Info( const CVector3D& Position, const CVector3D& Orientation );
-		Camera_Info( const CVector3D& Position, const CVector3D& Orientation, const CVector3D& Up );
-		Camera_Info( const CMatrix3D& Orientation );
-		Camera_Info( CCamera* copy );
-
-		void Initialise();
-		void Initialise( const CMatrix3D& Orientation );
-
-		void Freshen();
-		void Update();
-		void FreshenTarget();
-
-		~Camera_Info();
-/*
-
-		Camera_Info( const CVector3D& _position );
-		Camera_Info( const CVector3D& _position, const CVector3D& _orientation );
-		Camera_Info( const CVector3D& _position, const CVector3D& _orientation, const CVector3D& _up );
-		Camera_Info( CCamera* _copy );
-		void update();
-
-*/
-	};
-	extern JSClass JSI_class;
-	extern JSPropertySpec JSI_props[];
-	extern JSFunctionSpec JSI_methods[];
-
-	JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-	JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-
-	JSBool getCamera( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-	JSBool setCamera( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-
-	JSBool construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	void finalize( JSContext* cx, JSObject* obj );
-
-	JSBool lookAt( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool getFocus( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-
-    void init();
-}
-
-#endif
diff -r 6b3ac7e864ba source/graphics/scripting/JSInterface_LightEnv.cpp
--- a/source/graphics/scripting/JSInterface_LightEnv.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,250 +0,0 @@
-/* Copyright (C) 2009 Wildfire Games.
- * This file is part of 0 A.D.
- *
- * 0 A.D. is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * 0 A.D. 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Provide the LightEnv object type for JavaScript
- */
-
-#include "precompiled.h"
-
-#include "maths/scripting/JSInterface_Vector3D.h"
-
-#include "graphics/scripting/JSInterface_LightEnv.h"
-#include "graphics/LightEnv.h"
-
-#include "ps/World.h"
-
-#include "scripting/JSConversions.h"
-
-
-namespace JSI_LightEnv {
-
-namespace {
-
-extern JSClass JSI_class;
-
-/**
- * This enumeration is used to index properties with the JavaScript implementation.
- */
-enum
-{
-	lightenv_elevation,
-	lightenv_rotation,
-	lightenv_terrainShadowTransparency,
-	lightenv_sun,
-	lightenv_terrainAmbient,
-	lightenv_unitsAmbient
-};
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// LightEnv_Info, the private structure that holds data for individual LightEnv objects
-
-struct LightEnv_Info : public IPropertyOwner
-{
-	CLightEnv* m_Data;
-	bool m_EngineOwned;
-
-	// Create a new LightEnv that will only be used by JavaScript
-	LightEnv_Info()
-	{
-		m_Data = new CLightEnv;
-		m_EngineOwned = false;
-	}
-
-	// Use the given CLightEnv from the engine. The caller must guarantee that
-	// the copy object will not be deleted.
-	LightEnv_Info(CLightEnv* copy)
-	{
-		m_Data = copy;
-		m_EngineOwned = true;
-	}
-
-	~LightEnv_Info()
-	{
-		if (!m_EngineOwned)
-			delete m_Data;
-	}
-};
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Construction and finalization of LightEnvs
-
-/**
- * construct: the LightEnv constructor has been called from JavaScript, so create a new
- * LightEnv object
- */
-JSBool construct(JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval)
-{
-	JSObject* lightenv = JS_NewObject(cx, &JSI_class, NULL, NULL);
-
-	JSU_REQUIRE_NO_PARAMS();
-
-	JS_SetPrivate(cx, lightenv, new LightEnv_Info);
-	*rval = OBJECT_TO_JSVAL(lightenv);
-	return JS_TRUE;
-}
-
-/**
- * finalize: callback from the JS engine to indicate we should free our private data
- */
-void finalize(JSContext* cx, JSObject* obj)
-{
-	delete (LightEnv_Info*)JS_GetPrivate(cx, obj);
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Accessing properties of a LightEnv object
-
-// Can't use ToJSVal here because we need live updates from the vectors
-JSBool getVectorProperty(JSContext* cx, LightEnv_Info* lightenvInfo, CVector3D* vec, jsval* vp)
-{
-	JSObject* vector3d = JS_NewObject(cx, &JSI_Vector3D::JSI_class, NULL, NULL);
-	JS_SetPrivate(cx, vector3d, new JSI_Vector3D::Vector3D_Info(vec, lightenvInfo));
-	*vp = OBJECT_TO_JSVAL(vector3d);
-	return JS_TRUE;
-}
-
-
-JSBool getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
-{
-	if (!JSVAL_IS_INT(id))
-		return JS_TRUE ;
-
-	LightEnv_Info* lightenvInfo = (LightEnv_Info*)JS_GetPrivate(cx, obj);
-	if (!lightenvInfo)
-	{
-		JS_ReportError(cx, "[LightEnv] Invalid Reference");
-		return JS_TRUE;
-	}
-
-	CLightEnv* lightenv = lightenvInfo->m_Data;
-
-	switch(ToPrimitive<int>(id)) {
-	case lightenv_elevation: *vp = ToJSVal(lightenv->GetElevation()); break;
-	case lightenv_rotation: *vp = ToJSVal(lightenv->GetRotation()); break;
-	case lightenv_terrainShadowTransparency: *vp = ToJSVal(lightenv->GetTerrainShadowTransparency()); break;
-	case lightenv_sun: return getVectorProperty(cx, lightenvInfo, &lightenv->m_SunColor, vp);
-	case lightenv_terrainAmbient: return getVectorProperty(cx, lightenvInfo, &lightenv->m_TerrainAmbientColor, vp);
-	case lightenv_unitsAmbient: return getVectorProperty(cx, lightenvInfo, &lightenv->m_UnitsAmbientColor, vp);
-	default: break;
-	}
-
-	return JS_TRUE;
-}
-
-
-JSBool setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
-{
-	if (!JSVAL_IS_INT(id))
-		return( JS_TRUE );
-
-	LightEnv_Info* lightenvInfo = (LightEnv_Info*)JS_GetPrivate(cx, obj);
-	if (!lightenvInfo)
-	{
-		JS_ReportError(cx, "[LightEnv] Invalid reference");
-		return JS_TRUE;
-	}
-
-	CLightEnv* lightenv = lightenvInfo->m_Data;
-
-	switch(ToPrimitive<int>(id)) {
-	case lightenv_elevation: lightenv->SetElevation(ToPrimitive<float>(*vp)); break;
-	case lightenv_rotation: lightenv->SetRotation(ToPrimitive<float>(*vp)); break;
-	case lightenv_terrainShadowTransparency: lightenv->SetTerrainShadowTransparency(ToPrimitive<float>(*vp)); break;
-	case lightenv_sun: lightenv->m_SunColor = ToPrimitive<CVector3D>(*vp); break;
-	case lightenv_terrainAmbient: lightenv->m_TerrainAmbientColor = ToPrimitive<CVector3D>(*vp); break;
-	case lightenv_unitsAmbient: lightenv->m_UnitsAmbientColor = ToPrimitive<CVector3D>(*vp); break;
-	default: break;
-	}
-
-	return JS_TRUE;
-}
-
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Registration of LightEnv class with JavaScript
-
-JSClass JSI_class = {
-	"LightEnv", JSCLASS_HAS_PRIVATE,
-	JS_PropertyStub, JS_PropertyStub,
-	getProperty, setProperty,
-	JS_EnumerateStub, JS_ResolveStub,
-	JS_ConvertStub, finalize,
-	NULL, NULL, NULL, NULL
-};
-
-JSPropertySpec JSI_props[] =
-{
-	{ "elevation", lightenv_elevation, JSPROP_ENUMERATE },
-	{ "rotation", lightenv_rotation, JSPROP_ENUMERATE },
-	{ "terrainShadowTransparency", lightenv_terrainShadowTransparency, JSPROP_ENUMERATE },
-	{ "sun", lightenv_sun, JSPROP_ENUMERATE },
-	{ "terrainAmbient", lightenv_terrainAmbient, JSPROP_ENUMERATE },
-	{ "unitsAmbient", lightenv_unitsAmbient, JSPROP_ENUMERATE },
-	{ 0 },
-};
-
-JSFunctionSpec JSI_methods[] =
-{
-	{ 0 }
-};
-
-} // anonymous namespace
-
-/**
- * init: called by GameSetup to register the LightEnv class with the JS engine.
- */
-void init()
-{
-	g_ScriptingHost.DefineCustomObjectType( &JSI_class, construct, 0, JSI_props, JSI_methods, NULL, NULL );
-}
-
-
-///////////////////////////////////////////////////////////////////////////////////////////////
-// Accessing the global lightenv
-
-JSBool getLightEnv(JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp)
-{
-	JSObject* lightenv = JS_NewObject(cx, &JSI_class, NULL, NULL);
-	JS_SetPrivate(cx, lightenv, new LightEnv_Info(&g_LightEnv));
-	*vp = OBJECT_TO_JSVAL(lightenv);
-	return JS_TRUE;
-}
-
-JSBool setLightEnv(JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp)
-{
-	JSObject* lightenv = JSVAL_TO_OBJECT(*vp);
-	LightEnv_Info* lightenvInfo;
-
-	if (!JSVAL_IS_OBJECT(*vp) || NULL == (lightenvInfo = (LightEnv_Info*)JS_GetInstancePrivate(cx, lightenv, &JSI_class, NULL)))
-	{
-		JS_ReportError( cx, "[LightEnv] Invalid object" );
-	}
-	else
-	{
-		g_LightEnv = *lightenvInfo->m_Data;
-	}
-
-	return JS_TRUE;
-}
-
-} // namespace JSI_LightEnv
-
-
diff -r 6b3ac7e864ba source/graphics/scripting/JSInterface_LightEnv.h
--- a/source/graphics/scripting/JSInterface_LightEnv.h	Wed Nov 03 17:52:07 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/* Copyright (C) 2009 Wildfire Games.
- * This file is part of 0 A.D.
- *
- * 0 A.D. is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * 0 A.D. 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 General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Provide the LightEnv object type for JavaScript
- */
-
-#ifndef INCLUDED_JSI_LIGHTENV
-#define INCLUDED_JSI_LIGHTENV
-
-#include "scripting/ScriptingHost.h"
-
-namespace JSI_LightEnv
-{
-	void init();
-	JSBool getLightEnv( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-	JSBool setLightEnv( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-}
-
-#endif
diff -r 6b3ac7e864ba source/gui/CGUI.cpp
--- a/source/gui/CGUI.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/CGUI.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -326,6 +326,16 @@
 		&IGUIObject::ScriptEvent, EventName.LowerCase());
 }
 
+
+// Class needed for constructor
+static JSClass global_class = {
+	"global", JSCLASS_GLOBAL_FLAGS,
+	JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+	JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+	NULL, NULL, NULL, NULL,
+	NULL, NULL, NULL, NULL
+};
+
 //-------------------------------------------------------------------
 //  Constructor / Destructor
 //-------------------------------------------------------------------
@@ -334,10 +344,15 @@
 	m_BaseObject = new CGUIDummyObject;
 	m_BaseObject->SetGUI(this);
 
-	// Construct the parent object for all GUI JavaScript things
-	m_ScriptObject = JS_NewObject(g_ScriptingHost.getContext(), NULL, g_ScriptingHost.GetGlobalObject(), NULL);
-	debug_assert(m_ScriptObject != NULL); // How should it handle errors?
-	JS_AddRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
+	// Construct the root object for all GUI JavaScript things
+	// (We need an object with no parent, so functions defined by scripts get
+	// put onto this object and not its parent. In the current version of SpiderMonkey
+	// that means it must be a global object. Then we adjust its prototype so it
+	// can still read standard properties from the context's standard global object.)
+	m_ScriptObject = JS_NewGlobalObject(g_ScriptingHost.getContext(), &global_class);
+	JS_AddObjectRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
+
+	JS_SetPrototype(g_ScriptingHost.getContext(), m_ScriptObject, g_ScriptingHost.GetGlobalObject());
 }
 
 CGUI::~CGUI()
@@ -350,7 +365,7 @@
 	if (m_ScriptObject)
 	{
 		// Let it be garbage-collected
-		JS_RemoveRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
+		JS_RemoveObjectRoot(g_ScriptingHost.getContext(), &m_ScriptObject);
 	}
 }
 
diff -r 6b3ac7e864ba source/gui/GUIManager.cpp
--- a/source/gui/GUIManager.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/GUIManager.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -48,22 +48,6 @@
 	return g_GUI->HandleEvent(ev);
 }
 
-CGUIManager::SGUIPage::SGUIPage()
-{
-	JS_AddNamedRoot(g_ScriptingHost.GetContext(), &initData, "SGUIPage initData");
-}
-
-CGUIManager::SGUIPage::SGUIPage(const SGUIPage& page)
-{
-	*this = page;
-	JS_AddNamedRoot(g_ScriptingHost.GetContext(), &initData, "SGUIPage initData copy");
-}
-
-CGUIManager::SGUIPage::~SGUIPage()
-{
-	JS_RemoveRoot(g_ScriptingHost.GetContext(), &initData);
-}
-
 CGUIManager::CGUIManager(ScriptInterface& scriptInterface) :
 	m_ScriptInterface(scriptInterface)
 {
@@ -90,7 +74,7 @@
 {
 	m_PageStack.push_back(SGUIPage());
 	m_PageStack.back().name = pageName;
-	m_PageStack.back().initData = initData;
+	m_PageStack.back().initData = CScriptValRooted(m_ScriptInterface.GetContext(), initData);
 	LoadPage(m_PageStack.back());
 }
 
diff -r 6b3ac7e864ba source/gui/GUIManager.h
--- a/source/gui/GUIManager.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/GUIManager.h	Thu Nov 04 14:52:01 2010 +0000
@@ -135,15 +135,11 @@
 private:
 	struct SGUIPage
 	{
-		SGUIPage();
-		SGUIPage(const SGUIPage&);
-		~SGUIPage();
-
 		CStrW name;
 		std::set<VfsPath> inputs; // for hotloading
 
 		JSContext* cx;
-		CScriptVal initData; // data to be passed to the init() function
+		CScriptValRooted initData; // data to be passed to the init() function
 
 		shared_ptr<CGUI> gui; // the actual GUI page
 	};
diff -r 6b3ac7e864ba source/gui/IGUIObject.cpp
--- a/source/gui/IGUIObject.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/IGUIObject.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -90,13 +90,13 @@
 		std::map<CStr, JSObject**>::iterator it;
 		for (it = m_ScriptHandlers.begin(); it != m_ScriptHandlers.end(); ++it)
 		{
-			JS_RemoveRoot(g_ScriptingHost.getContext(), it->second);
+			JS_RemoveObjectRoot(g_ScriptingHost.getContext(), it->second);
 			delete it->second;
 		}
 	}
 	
 	if (m_JSObject)
-		JS_RemoveRoot(g_ScriptingHost.getContext(), &m_JSObject);
+		JS_RemoveObjectRoot(g_ScriptingHost.getContext(), &m_JSObject);
 }
 
 //-------------------------------------------------------------------
@@ -488,11 +488,11 @@
 {
 	JSObject** obj = new JSObject*;
 	*obj = Function;
-	JS_AddRoot(g_ScriptingHost.getContext(), obj);
+	JS_AddObjectRoot(g_ScriptingHost.getContext(), obj);
 
 	if (m_ScriptHandlers[Action])
 	{
-		JS_RemoveRoot(g_ScriptingHost.getContext(), m_ScriptHandlers[Action]);
+		JS_RemoveObjectRoot(g_ScriptingHost.getContext(), m_ScriptHandlers[Action]);
 		delete m_ScriptHandlers[Action];
 	}
 	m_ScriptHandlers[Action] = obj;
@@ -504,10 +504,6 @@
 	if (it == m_ScriptHandlers.end())
 		return;
 
-	// PRIVATE_TO_JSVAL assumes two-byte alignment,
-	// so make sure that's always true
-	debug_assert(! ((jsval)this & JSVAL_INT));
-
 	// The IGUIObject needs to be stored inside the script's object
 	jsval guiObject = PRIVATE_TO_JSVAL(this);
 
@@ -517,9 +513,6 @@
 	
 	// TODO: why don't we use GetJSObject here?
 
-	// Prevent it from being garbage-collected before it's passed into the function
-	JS_AddRoot(g_ScriptingHost.getContext(), &jsGuiObject);
-
 	// Set up the 'mouse' parameter
 	jsval mouseParams[3];
 	mouseParams[0] = INT_TO_JSVAL(m_pGUI->m_MousePos.x);
@@ -528,9 +521,6 @@
 	JSObject* mouseObj = JS_ConstructObjectWithArguments(g_ScriptingHost.getContext(), &JSI_GUIMouse::JSI_class, m_pGUI->m_ScriptObject, NULL, 3, mouseParams);
 	debug_assert(mouseObj); // TODO: Handle errors
 
-	// Don't garbage collect the mouse
-	JS_AddRoot(g_ScriptingHost.getContext(), &mouseObj);
-
 	jsval paramData[] = { OBJECT_TO_JSVAL(mouseObj) };
 
 	jsval result;
@@ -539,10 +529,6 @@
 	{
 		JS_ReportError(g_ScriptingHost.getContext(), "Errors executing script action \"%s\"", Action.c_str());
 	}
-
-	// Allow the temporary parameters to be garbage-collected
-	JS_RemoveRoot(g_ScriptingHost.getContext(), &mouseObj);
-	JS_RemoveRoot(g_ScriptingHost.getContext(), &jsGuiObject);
 }
 
 void IGUIObject::ScriptEvent(const CStr& Action, const CScriptValRooted& Argument)
@@ -571,7 +557,7 @@
 	if (! m_JSObject)
 	{
 		m_JSObject = JS_NewObject(g_ScriptingHost.getContext(), &JSI_IGUIObject::JSI_class, NULL, NULL);
-		JS_AddRoot(g_ScriptingHost.getContext(), &m_JSObject);
+		JS_AddObjectRoot(g_ScriptingHost.getContext(), &m_JSObject);
 		JS_SetPrivate(g_ScriptingHost.getContext(), m_JSObject, this);
 	}
 	return m_JSObject;
diff -r 6b3ac7e864ba source/gui/IGUIObject.h
--- a/source/gui/IGUIObject.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/IGUIObject.h	Thu Nov 04 14:52:01 2010 +0000
@@ -145,8 +145,8 @@
 	friend class GUITooltip;
 
 	// Allow getProperty to access things like GetParent()
-	friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
-	friend JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
+	friend JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
+	friend JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
 
 public:
 	IGUIObject();
diff -r 6b3ac7e864ba source/gui/scripting/JSInterface_GUITypes.cpp
--- a/source/gui/scripting/JSInterface_GUITypes.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/scripting/JSInterface_GUITypes.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -45,30 +45,32 @@
 
 JSFunctionSpec JSI_GUISize::JSI_methods[] = 
 {
-	{ "toString", JSI_GUISize::toString, 0, 0, 0 },
+	{ "toString", JSI_GUISize::toString, 0, 0 },
 	{ 0 }
 };
 
-JSBool JSI_GUISize::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval))
+JSBool JSI_GUISize::construct(JSContext* cx, uintN argc, jsval* vp)
 {
+	JSObject* obj = JS_NewObject(cx, &JSI_GUISize::JSI_class, NULL, NULL);
+
 	if (argc == 8)
 	{
-		JS_SetProperty(cx, obj, "left",		&argv[0]);
-		JS_SetProperty(cx, obj, "top",		&argv[1]);
-		JS_SetProperty(cx, obj, "right",	&argv[2]);
-		JS_SetProperty(cx, obj, "bottom",	&argv[3]);
-		JS_SetProperty(cx, obj, "rleft",	&argv[4]);
-		JS_SetProperty(cx, obj, "rtop",		&argv[5]);
-		JS_SetProperty(cx, obj, "rright",	&argv[6]);
-		JS_SetProperty(cx, obj, "rbottom",	&argv[7]);
+		JS_SetProperty(cx, obj, "left",		&JS_ARGV(cx, vp)[0]);
+		JS_SetProperty(cx, obj, "top",		&JS_ARGV(cx, vp)[1]);
+		JS_SetProperty(cx, obj, "right",	&JS_ARGV(cx, vp)[2]);
+		JS_SetProperty(cx, obj, "bottom",	&JS_ARGV(cx, vp)[3]);
+		JS_SetProperty(cx, obj, "rleft",	&JS_ARGV(cx, vp)[4]);
+		JS_SetProperty(cx, obj, "rtop",		&JS_ARGV(cx, vp)[5]);
+		JS_SetProperty(cx, obj, "rright",	&JS_ARGV(cx, vp)[6]);
+		JS_SetProperty(cx, obj, "rbottom",	&JS_ARGV(cx, vp)[7]);
 	}
 	else if (argc == 4)
 	{
 		jsval zero = JSVAL_ZERO;
-		JS_SetProperty(cx, obj, "left",		&argv[0]);
-		JS_SetProperty(cx, obj, "top",		&argv[1]);
-		JS_SetProperty(cx, obj, "right",	&argv[2]);
-		JS_SetProperty(cx, obj, "bottom",	&argv[3]);
+		JS_SetProperty(cx, obj, "left",		&JS_ARGV(cx, vp)[0]);
+		JS_SetProperty(cx, obj, "top",		&JS_ARGV(cx, vp)[1]);
+		JS_SetProperty(cx, obj, "right",	&JS_ARGV(cx, vp)[2]);
+		JS_SetProperty(cx, obj, "bottom",	&JS_ARGV(cx, vp)[3]);
 		JS_SetProperty(cx, obj, "rleft",	&zero);
 		JS_SetProperty(cx, obj, "rtop",		&zero);
 		JS_SetProperty(cx, obj, "rright",	&zero);
@@ -87,6 +89,7 @@
 		JS_SetProperty(cx, obj, "rbottom",	&zero);
 	}
 
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
 	return JS_TRUE;
 }
 
@@ -99,13 +102,15 @@
 		return CStr(per)+CStr("%")+( pix == 0.0 ? CStr() : pix > 0.0 ? CStr("+")+CStr(pix) : CStr(pix) );
 }
 
-JSBool JSI_GUISize::toString(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
+JSBool JSI_GUISize::toString(JSContext* cx, uintN argc, jsval* vp)
 {
+	UNUSED2(argc);
+
 	CStr buffer;
 
 	try
 	{
-#define SIDE(side) buffer += ToPercentString(g_ScriptingHost.GetObjectProperty_Double(obj, #side), g_ScriptingHost.GetObjectProperty_Double(obj, "r"#side));
+#define SIDE(side) buffer += ToPercentString(g_ScriptingHost.GetObjectProperty_Double(JS_THIS_OBJECT(cx, vp), #side), g_ScriptingHost.GetObjectProperty_Double(JS_THIS_OBJECT(cx, vp), "r"#side));
 		SIDE(left);
 		buffer += " ";
 		SIDE(top);
@@ -117,11 +122,11 @@
 	}
 	catch (PSERROR_Scripting_ConversionFailed)
 	{
-		*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "<Error converting value to numbers>"));
+		JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "<Error converting value to numbers>")));
 		return JS_TRUE;
 	}
 
-	*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer.c_str()));
+	JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer.c_str())));
 	return JS_TRUE;
 }
 
@@ -149,45 +154,57 @@
 
 JSFunctionSpec JSI_GUIColor::JSI_methods[] = 
 {
-	{ "toString", JSI_GUIColor::toString, 0, 0, 0 },
+	{ "toString", JSI_GUIColor::toString, 0, 0 },
 	{ 0 }
 };
 
-JSBool JSI_GUIColor::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval))
+JSBool JSI_GUIColor::construct(JSContext* cx, uintN argc, jsval* vp)
 {
+	JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL);
+
 	if (argc == 4)
 	{
-		JS_SetProperty(cx, obj, "r", &argv[0]);
-		JS_SetProperty(cx, obj, "g", &argv[1]);
-		JS_SetProperty(cx, obj, "b", &argv[2]);
-		JS_SetProperty(cx, obj, "a", &argv[3]);
+		JS_SetProperty(cx, obj, "r", &JS_ARGV(cx, vp)[0]);
+		JS_SetProperty(cx, obj, "g", &JS_ARGV(cx, vp)[1]);
+		JS_SetProperty(cx, obj, "b", &JS_ARGV(cx, vp)[2]);
+		JS_SetProperty(cx, obj, "a", &JS_ARGV(cx, vp)[3]);
 	}
 	else
 	{
 		// Nice magenta:
-		jsval r = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
-		JS_SetProperty(cx, obj, "r", &r);
-		jsval g = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 0.0));
-		JS_SetProperty(cx, obj, "g", &g);
-		jsval b = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
-		JS_SetProperty(cx, obj, "b", &b);
-		jsval a = DOUBLE_TO_JSVAL(JS_NewDouble(cx, 1.0));
-		JS_SetProperty(cx, obj, "a", &a);
+		jsval c;
+		if (!JS_NewNumberValue(cx, 1.0, &c))
+			return JS_FALSE;
+		JS_SetProperty(cx, obj, "r", &c);
+		JS_SetProperty(cx, obj, "b", &c);
+		JS_SetProperty(cx, obj, "a", &c);
+		if (!JS_NewNumberValue(cx, 0.0, &c))
+			return JS_FALSE;
+		JS_SetProperty(cx, obj, "g", &c);
 	}
+
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
 	return JS_TRUE;
 }
 
-JSBool JSI_GUIColor::toString(JSContext* cx, JSObject* obj,
-	uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
+JSBool JSI_GUIColor::toString(JSContext* cx, uintN argc, jsval* vp)
 {
+	UNUSED2(argc);
+
+	jsdouble r, g, b, a;
+	if (!JS_ValueToNumber(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "r"), &r)) return JS_FALSE;
+	if (!JS_ValueToNumber(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "g"), &g)) return JS_FALSE;
+	if (!JS_ValueToNumber(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "b"), &b)) return JS_FALSE;
+	if (!JS_ValueToNumber(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "a"), &a)) return JS_FALSE;
+
 	char buffer[256];
 	// Convert to integers, to be compatible with the GUI's string SetSetting
 	snprintf(buffer, 256, "%d %d %d %d",
-		(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "r")) ),
-		(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "g")) ),
-		(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "b")) ),
-		(int)( 255.0 * *JSVAL_TO_DOUBLE(g_ScriptingHost.GetObjectProperty(obj, "a")) ));
-	*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
+		(int)(255.0 * r),
+		(int)(255.0 * g),
+		(int)(255.0 * b),
+		(int)(255.0 * a));
+	JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
 	return JS_TRUE;
 }
 
@@ -213,17 +230,19 @@
 
 JSFunctionSpec JSI_GUIMouse::JSI_methods[] = 
 {
-	{ "toString", JSI_GUIMouse::toString, 0, 0, 0 },
+	{ "toString", JSI_GUIMouse::toString, 0, 0 },
 	{ 0 }
 };
 
-JSBool JSI_GUIMouse::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval))
+JSBool JSI_GUIMouse::construct(JSContext* cx, uintN argc, jsval* vp)
 {
+	JSObject* obj = JS_NewObject(cx, &JSI_GUIMouse::JSI_class, NULL, NULL);
+
 	if (argc == 3)
 	{
-		JS_SetProperty(cx, obj, "x", &argv[0]);
-		JS_SetProperty(cx, obj, "y", &argv[1]);
-		JS_SetProperty(cx, obj, "buttons", &argv[2]);
+		JS_SetProperty(cx, obj, "x", &JS_ARGV(cx, vp)[0]);
+		JS_SetProperty(cx, obj, "y", &JS_ARGV(cx, vp)[1]);
+		JS_SetProperty(cx, obj, "buttons", &JS_ARGV(cx, vp)[2]);
 	}
 	else
 	{
@@ -232,17 +251,23 @@
 		JS_SetProperty(cx, obj, "y", &zero);
 		JS_SetProperty(cx, obj, "buttons", &zero);
 	}
+
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
 	return JS_TRUE;
 }
 
-JSBool JSI_GUIMouse::toString(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
+JSBool JSI_GUIMouse::toString(JSContext* cx, uintN argc, jsval* vp)
 {
+	UNUSED2(argc);
+
+	int32 x, y, buttons;
+	if (!JS_ValueToECMAInt32(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "x"), &x)) return JS_FALSE;
+	if (!JS_ValueToECMAInt32(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "y"), &y)) return JS_FALSE;
+	if (!JS_ValueToECMAInt32(cx, g_ScriptingHost.GetObjectProperty(JS_THIS_OBJECT(cx, vp), "buttons"), &buttons)) return JS_FALSE;
+
 	char buffer[256];
-	snprintf(buffer, 256, "%d %d %d",
-		JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "x")),
-		JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "y")),
-		JSVAL_TO_INT(g_ScriptingHost.GetObjectProperty(obj, "buttons")) );
-	*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
+	snprintf(buffer, 256, "%d %d %d", x, y, buttons);
+	JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
 	return JS_TRUE;
 }
 
diff -r 6b3ac7e864ba source/gui/scripting/JSInterface_GUITypes.h
--- a/source/gui/scripting/JSInterface_GUITypes.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/scripting/JSInterface_GUITypes.h	Thu Nov 04 14:52:01 2010 +0000
@@ -26,8 +26,8 @@
 		extern JSClass JSI_class;				\
 		extern JSPropertySpec JSI_props[];		\
 		extern JSFunctionSpec JSI_methods[];	\
-		JSBool construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );	\
-		JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );	\
+		JSBool construct(JSContext* cx, uintN argc, jsval* vp);	\
+		JSBool toString(JSContext* cx, uintN argc, jsval* vp);	\
 	}
 
 GUISTDTYPE(Size)
diff -r 6b3ac7e864ba source/gui/scripting/JSInterface_IGUIObject.cpp
--- a/source/gui/scripting/JSInterface_IGUIObject.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/scripting/JSInterface_IGUIObject.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -46,15 +46,23 @@
 
 JSFunctionSpec JSI_IGUIObject::JSI_methods[] = 
 {
-	{ "toString", JSI_IGUIObject::toString, 0, 0, 0 },
-	{ "focus", JSI_IGUIObject::focus, 0, 0, 0 },
-	{ "blur", JSI_IGUIObject::blur, 0, 0, 0 },
+	{ "toString", JSI_IGUIObject::toString, 0, 0 },
+	{ "focus", JSI_IGUIObject::focus, 0, 0 },
+	{ "blur", JSI_IGUIObject::blur, 0, 0 },
 	{ 0 }
 };
 
-JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
+JSBool JSI_IGUIObject::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
 {
-	CStr propName = JS_GetStringBytes(JS_ValueToString(cx, id));
+	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
+	if (!e)
+		return JS_FALSE;
+
+	jsval idval;
+	if (!JS_IdToValue(cx, id, &idval))
+		return JS_FALSE;
+
+	CStr propName = g_ScriptingHost.ValueToString(idval);
 
 	// Skip some things which are known to be functions rather than properties.
 	// ("constructor" *must* be here, else it'll try to GetSettingType before
@@ -69,8 +77,6 @@
 	   )
 		return JS_TRUE;
 
-	IGUIObject* e = (IGUIObject*)JS_GetPrivate(cx, obj);
-
 	// Use onWhatever to access event handlers
 	if (propName.Left(2) == "on")
 	{
@@ -143,8 +149,7 @@
 				float value;
 				GUI<float>::GetSetting(e, propName, value);
 				// Create a garbage-collectable double
-				*vp = DOUBLE_TO_JSVAL(JS_NewDouble(cx, value) );
-				break;
+				return JS_NewNumberValue(cx, value, vp);
 			}
 
 		case GUIST_CColor:
@@ -154,8 +159,9 @@
 				JSObject* obj = JS_NewObject(cx, &JSI_GUIColor::JSI_class, NULL, NULL);
 				*vp = OBJECT_TO_JSVAL(obj); // root it
 
+				jsval c;
 				// Attempt to minimise ugliness through macrosity
-				#define P(x) jsval x = DOUBLE_TO_JSVAL(JS_NewDouble(cx, colour.x)); JS_SetProperty(cx, obj, #x, &x)
+				#define P(x) if (!JS_NewNumberValue(cx, colour.x, &c)) return JS_FALSE; JS_SetProperty(cx, obj, #x, &c)
 					P(r);
 					P(g);
 					P(b);
@@ -286,10 +292,18 @@
 	}
 }
 
-JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp)
+JSBool JSI_IGUIObject::setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
 {
-	IGUIObject* e = (IGUIObject*)JS_GetPrivate(cx, obj);
-	CStr propName = g_ScriptingHost.ValueToString(id);
+	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, obj, &JSI_IGUIObject::JSI_class, NULL);
+	if (!e)
+		return JS_FALSE;
+
+	jsval idval;
+	if (!JS_IdToValue(cx, id, &idval))
+		return JS_FALSE;
+
+	CStr propName = g_ScriptingHost.ValueToString(idval);
+
 	if (propName == "name")
 	{
 		CStr propValue = JS_GetStringBytes(JS_ValueToString(cx, *vp));
@@ -549,7 +563,7 @@
 }
 
 
-JSBool JSI_IGUIObject::construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval))
+JSBool JSI_IGUIObject::construct(JSContext* cx, uintN argc, jsval* vp)
 {
 	if (argc == 0)
 	{
@@ -557,12 +571,13 @@
 		return JS_FALSE;
 	}
 
-	debug_assert(argc == 1);
+	JSObject* obj = JS_NewObject(cx, &JSI_IGUIObject::JSI_class, NULL, NULL);
 
 	// Store the IGUIObject in the JS object's 'private' area
-	IGUIObject* guiObject = (IGUIObject*)JSVAL_TO_PRIVATE(argv[0]);
+	IGUIObject* guiObject = (IGUIObject*)JSVAL_TO_PRIVATE(JS_ARGV(cx, vp)[0]);
 	JS_SetPrivate(cx, obj, guiObject);
 
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(obj));
 	return JS_TRUE;
 }
 
@@ -571,28 +586,40 @@
 	g_ScriptingHost.DefineCustomObjectType(&JSI_class, construct, 1, JSI_props, JSI_methods, NULL, NULL);
 }
 
-JSBool JSI_IGUIObject::toString(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval)
+JSBool JSI_IGUIObject::toString(JSContext* cx, uintN argc, jsval* vp)
 {
-	IGUIObject* e = (IGUIObject*)JS_GetPrivate( cx, obj );
+	UNUSED2(argc);
+
+	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
+	if (!e)
+		return JS_FALSE;
 
 	char buffer[256];
 	snprintf(buffer, 256, "[GUIObject: %s]", e->GetName().c_str());
 	buffer[255] = 0;
-	*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer));
+	JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
 	return JS_TRUE;
 }
 
-JSBool JSI_IGUIObject::focus(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* UNUSED(rval))
+JSBool JSI_IGUIObject::focus(JSContext* cx, uintN argc, jsval* vp)
 {
-	IGUIObject* e = (IGUIObject*)JS_GetPrivate( cx, obj );
+	UNUSED2(argc);
+
+	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
+	if (!e)
+		return JS_FALSE;
 
 	e->GetGUI()->SetFocusedObject(e);
 	return JS_TRUE;
 }
 
-JSBool JSI_IGUIObject::blur(JSContext* cx, JSObject* obj, uintN UNUSED(argc), jsval* UNUSED(argv), jsval* UNUSED(rval))
+JSBool JSI_IGUIObject::blur(JSContext* cx, uintN argc, jsval* vp)
 {
-	IGUIObject* e = (IGUIObject*)JS_GetPrivate( cx, obj );
+	UNUSED2(argc);
+
+	IGUIObject* e = (IGUIObject*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_IGUIObject::JSI_class, NULL);
+	if (!e)
+		return JS_FALSE;
 
 	e->GetGUI()->SetFocusedObject(NULL);
 	return JS_TRUE;
diff -r 6b3ac7e864ba source/gui/scripting/JSInterface_IGUIObject.h
--- a/source/gui/scripting/JSInterface_IGUIObject.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/gui/scripting/JSInterface_IGUIObject.h	Thu Nov 04 14:52:01 2010 +0000
@@ -25,14 +25,12 @@
 	extern JSClass JSI_class;
 	extern JSPropertySpec JSI_props[];
 	extern JSFunctionSpec JSI_methods[];
-	JSBool addProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
-	JSBool delProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
-	JSBool getProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
-	JSBool setProperty(JSContext* cx, JSObject* obj, jsval id, jsval* vp);
-	JSBool construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
-	JSBool toString(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
-	JSBool focus(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
-	JSBool blur(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval);
+	JSBool getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
+	JSBool setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
+	JSBool construct(JSContext* cx, uintN argc, jsval* vp);
+	JSBool toString(JSContext* cx, uintN argc, jsval* vp);
+	JSBool focus(JSContext* cx, uintN argc, jsval* vp);
+	JSBool blur(JSContext* cx, uintN argc, jsval* vp);
 	void init();
 }
 
diff -r 6b3ac7e864ba source/maths/scripting/JSInterface_Vector3D.cpp
--- a/source/maths/scripting/JSInterface_Vector3D.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/maths/scripting/JSInterface_Vector3D.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -21,11 +21,6 @@
 #include "scripting/JSConversions.h"
 #include "scripting/ScriptingHost.h"
 
-namespace JSI_Vector3D
-{
-	static CVector3D* GetVector( JSContext* cx, JSObject* obj );
-}
-
 JSClass JSI_Vector3D::JSI_class = {
 	"Vector3D", JSCLASS_HAS_PRIVATE,
 	JS_PropertyStub, JS_PropertyStub,
@@ -45,24 +40,13 @@
 
 JSFunctionSpec JSI_Vector3D::JSI_methods[] = 
 {
-	{ "toString", JSI_Vector3D::toString, 0, 0, 0 },
-	{ "add", JSI_Vector3D::add, 1, 0, 0 },
-	{ "subtract", JSI_Vector3D::subtract, 1, 0, 0 },
-	{ "minus", JSI_Vector3D::subtract, 1, 0, 0 },
-	{ "negate", JSI_Vector3D::negate, 1, 0, 0 },
-	{ "scale", JSI_Vector3D::scale, 1, 0, 0 },
-	{ "multiply", JSI_Vector3D::scale, 1, 0, 0 },
-	{ "divide", JSI_Vector3D::divide, 1, 0, 0 },
-	{ "dot", JSI_Vector3D::dot, 1, 0, 0 },
-	{ "cross", JSI_Vector3D::cross, 1, 0, 0 },
-	{ "length", JSI_Vector3D::length, 0, 0, 0 },
-	{ "normalize", JSI_Vector3D::normalize, 0, 0, 0 },
+	{ "toString", JSI_Vector3D::toString, 0, 0 },
 	{ 0 }
 };
 
 void JSI_Vector3D::init()
 {
-	g_ScriptingHost.DefineCustomObjectType( &JSI_class, JSI_Vector3D::construct, 0, JSI_props, JSI_methods, NULL, NULL );
+	g_ScriptingHost.DefineCustomObjectType(&JSI_class, JSI_Vector3D::construct, 0, JSI_props, JSI_methods, NULL, NULL);
 }
 
 JSI_Vector3D::Vector3D_Info::Vector3D_Info()
@@ -71,19 +55,19 @@
 	vector = new CVector3D();
 }
 
-JSI_Vector3D::Vector3D_Info::Vector3D_Info( float x, float y, float z )
+JSI_Vector3D::Vector3D_Info::Vector3D_Info(float x, float y, float z)
 {
 	owner = NULL;
-	vector = new CVector3D( x, y, z );
+	vector = new CVector3D(x, y, z);
 }
 
-JSI_Vector3D::Vector3D_Info::Vector3D_Info( const CVector3D& copy )
+JSI_Vector3D::Vector3D_Info::Vector3D_Info(const CVector3D& copy)
 {
 	owner = NULL;
-	vector = new CVector3D( copy.X, copy.Y, copy.Z );
+	vector = new CVector3D(copy.X, copy.Y, copy.Z);
 }
 
-JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner )
+JSI_Vector3D::Vector3D_Info::Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner)
 {
 	owner = _owner;
 	updateFn = NULL;
@@ -91,7 +75,7 @@
 	vector = attach;
 }
 
-JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner, void( IPropertyOwner::*_updateFn )(void) )
+JSI_Vector3D::Vector3D_Info::Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner, void(IPropertyOwner::*_updateFn)(void))
 {
 	owner = _owner;
 	updateFn = _updateFn;
@@ -99,7 +83,8 @@
 	vector = attach;
 }
 
-JSI_Vector3D::Vector3D_Info::Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner, void( IPropertyOwner::*_updateFn )(void), void( IPropertyOwner::*_freshenFn )(void) )
+JSI_Vector3D::Vector3D_Info::Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner, void(IPropertyOwner::*_updateFn)(void),
+		void(IPropertyOwner::*_freshenFn)(void))
 {
 	owner = _owner;
 	updateFn = _updateFn;
@@ -109,245 +94,116 @@
 
 JSI_Vector3D::Vector3D_Info::~Vector3D_Info()
 {
-	if( !owner ) delete( vector );
+	if (!owner)
+		delete (vector);
 }
 
-JSBool JSI_Vector3D::getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
+JSBool JSI_Vector3D::getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
 {
-	if( !JSVAL_IS_INT( id ) )
-		return( JS_TRUE );
+	if (!JSID_IS_INT(id))
+		return JS_TRUE;
 
-	Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
-	if( !vectorInfo )
+	Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate(cx, obj, &JSI_Vector3D::JSI_class, NULL);
+	if (!vectorInfo)
+		return JS_FALSE;
+
+	CVector3D* vectorData = vectorInfo->vector;
+
+	if (vectorInfo->owner && vectorInfo->freshenFn)
+		((vectorInfo->owner)->*(vectorInfo->freshenFn))();
+
+	switch (JSID_TO_INT(id))
 	{
-		JS_ReportError( cx, "[Vector3D] Invalid reference" );
-		return( JS_TRUE );
+	case component_x:
+		return JS_NewNumberValue(cx, vectorData->X, vp);
+	case component_y:
+		return JS_NewNumberValue(cx, vectorData->Y, vp);
+	case component_z:
+		return JS_NewNumberValue(cx, vectorData->Z, vp);
 	}
 
- 	CVector3D* vectorData = vectorInfo->vector;
+	return JS_FALSE;
+}
 
-	if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
-	
-	switch( ToPrimitive<int>( id ) )
+JSBool JSI_Vector3D::setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
+{
+	if (!JSID_IS_INT(id))
+		return JS_TRUE;
+
+	Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate(cx, obj, &JSI_Vector3D::JSI_class, NULL);
+	if (!vectorInfo)
+		return JS_FALSE;
+
+	CVector3D* vectorData = vectorInfo->vector;
+
+	if (vectorInfo->owner && vectorInfo->freshenFn)
+		((vectorInfo->owner)->*(vectorInfo->freshenFn))();
+
+	switch (JSID_TO_INT(id))
 	{
-	case component_x: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->X ) ); return( JS_TRUE );
-	case component_y: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->Y ) ); return( JS_TRUE );
-	case component_z: *vp = DOUBLE_TO_JSVAL( JS_NewDouble( cx, vectorData->Z ) ); return( JS_TRUE );
+	case component_x:
+		vectorData->X = ToPrimitive<float> (*vp);
+		break;
+	case component_y:
+		vectorData->Y = ToPrimitive<float> (*vp);
+		break;
+	case component_z:
+		vectorData->Z = ToPrimitive<float> (*vp);
+		break;
 	}
 
-	return( JS_FALSE );
+	if (vectorInfo->owner && vectorInfo->updateFn)
+		((vectorInfo->owner)->*(vectorInfo->updateFn))();
+
+	return JS_TRUE;
 }
 
-JSBool JSI_Vector3D::setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
+JSBool JSI_Vector3D::construct(JSContext* cx, uintN argc, jsval* vp)
 {
-	if( !JSVAL_IS_INT( id ) )
-		return( JS_TRUE );
+	JSObject* vector = JS_NewObject(cx, &JSI_Vector3D::JSI_class, NULL, NULL);
 
-	Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
-	if( !vectorInfo )
+	if (argc == 0)
 	{
-		JS_ReportError( cx, "[Vector3D] Invalid reference" );
-		return( JS_TRUE );
-	}
-	CVector3D* vectorData = vectorInfo->vector;
-
-	if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
-
-	switch( ToPrimitive<int>( id ) )
-	{
-	case component_x: vectorData->X = ToPrimitive<float>( *vp ); break;
-	case component_y: vectorData->Y = ToPrimitive<float>( *vp ); break;
-	case component_z: vectorData->Z = ToPrimitive<float>( *vp ); break;
-	}
-
-	
-	if( vectorInfo->owner && vectorInfo->updateFn ) ( (vectorInfo->owner)->*(vectorInfo->updateFn) )();
-
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::construct( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
-{
-	JSObject* vector = JS_NewObject( cx, &JSI_Vector3D::JSI_class, NULL, NULL );
-	
-	if( argc == 0 )
-	{
-		JS_SetPrivate( cx, vector, new Vector3D_Info() );
-		*rval = OBJECT_TO_JSVAL( vector );
-		return( JS_TRUE );
+		JS_SetPrivate(cx, vector, new Vector3D_Info());
+		JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(vector));
+		return JS_TRUE;
 	}
 
 	JSU_REQUIRE_PARAMS(3);
 	try
 	{
-		float x = ToPrimitive<float>( argv[0] );
-		float y = ToPrimitive<float>( argv[1] );
-		float z = ToPrimitive<float>( argv[2] );
-		JS_SetPrivate( cx, vector, new Vector3D_Info( x, y, z ) );
-		*rval = OBJECT_TO_JSVAL( vector );
-		return( JS_TRUE );
+		float x = ToPrimitive<float> (JS_ARGV(cx, vp)[0]);
+		float y = ToPrimitive<float> (JS_ARGV(cx, vp)[1]);
+		float z = ToPrimitive<float> (JS_ARGV(cx, vp)[2]);
+		JS_SetPrivate(cx, vector, new Vector3D_Info(x, y, z));
+		JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(vector));
+		return JS_TRUE;
 	}
 	catch (PSERROR_Scripting_ConversionFailed)
 	{
 		// Invalid input (i.e. can't be coerced into doubles) - fail
-		JS_ReportError( cx, "Invalid parameters to Vector3D constructor" );
-		*rval = JSVAL_NULL;
-		return( JS_FALSE );
+		JS_ReportError(cx, "Invalid parameters to Vector3D constructor");
+		return JS_FALSE;
 	}
 }
 
-void JSI_Vector3D::finalize( JSContext* cx, JSObject* obj )
+void JSI_Vector3D::finalize(JSContext* cx, JSObject* obj)
 {
-	delete( (Vector3D_Info*)JS_GetPrivate( cx, obj ) );
+	delete ((Vector3D_Info*)JS_GetPrivate(cx, obj));
 }
 
-JSBool JSI_Vector3D::toString( JSContext* cx, JSObject* obj,
-	uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
+JSBool JSI_Vector3D::toString(JSContext* cx, uintN argc, jsval* vp)
 {
 	char buffer[256];
-	Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetPrivate( cx, obj );
+	Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate(cx, JS_THIS_OBJECT(cx, vp), &JSI_Vector3D::JSI_class, NULL);
+	if (!vectorInfo)
+		return JS_FALSE;
 
-	if( !vectorInfo ) return( JS_TRUE );
+	if (vectorInfo->owner && vectorInfo->freshenFn)
+		((vectorInfo->owner)->*(vectorInfo->freshenFn))();
 
-	if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
-
- 	CVector3D* vectorData = vectorInfo->vector;
-	sprintf_s( buffer, ARRAY_SIZE(buffer), "[object Vector3D: ( %f, %f, %f )]", vectorData->X, vectorData->Y, vectorData->Z );
-	*rval = STRING_TO_JSVAL( JS_NewStringCopyZ( cx, buffer ) );
-	return( JS_TRUE );
+	CVector3D* vectorData = vectorInfo->vector;
+	sprintf_s(buffer, ARRAY_SIZE(buffer), "[object Vector3D: ( %f, %f, %f )]", vectorData->X, vectorData->Y, vectorData->Z);
+	JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buffer)));
+	return JS_TRUE;
 }
-
-CVector3D* JSI_Vector3D::GetVector( JSContext* cx, JSObject* obj )
-{
-	Vector3D_Info* vectorInfo = (Vector3D_Info*)JS_GetInstancePrivate( cx, obj, &JSI_class, NULL );
-	if( !vectorInfo )
-	{
-		JS_ReportError( cx, "[Vector3D] Invalid reference" );
-		return( NULL );
-	}
-	if( vectorInfo->owner && vectorInfo->freshenFn ) ( (vectorInfo->owner)->*(vectorInfo->freshenFn) )();
-	return( vectorInfo->vector );
-}
-
-#define GET_VECTORS\
-	CVector3D* a = GetVector( cx, obj );\
-	if(!a)\
-		return( JS_TRUE );\
-	if( ( argc == 0 ) || !JSVAL_IS_OBJECT( argv[0] ) )\
-	{\
-invalid_param:\
-		JS_ReportError( cx, "[Vector3D] Invalid parameter" );\
-		return( JS_TRUE );\
-	}\
-	CVector3D* b = GetVector( cx, JSVAL_TO_OBJECT( argv[0] ) );\
-	if(!b)\
-		goto invalid_param;
-
-#define GET_VECTOR_AND_FLOAT\
-	CVector3D* v = GetVector( cx, obj );\
-	if(!v)\
-		return( JS_TRUE );\
-	float f;\
-	if( ( argc == 0 ) || !ToPrimitive( cx, argv[0], f ) )\
-	{\
-		JS_ReportError( cx, "Invalid parameter" );\
-		return( JS_TRUE );\
-	}
-
-
-JSBool JSI_Vector3D::add( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
-{
-	GET_VECTORS;
-
-	JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
-	JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *a + *b ) );
-	*rval = OBJECT_TO_JSVAL( vector3d );
-
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::subtract( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
-{
-	GET_VECTORS;
-
-	JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
-	JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *a - *b ) );
-	*rval = OBJECT_TO_JSVAL( vector3d );
-
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::negate( JSContext* cx, JSObject* obj,
-	uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
-{
-	CVector3D* v = GetVector( cx, obj );
-	if(!v)
-		return( JS_TRUE );
-
-	*rval = ToJSVal( -( *v ) );
-
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::scale( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
-{
-	GET_VECTOR_AND_FLOAT;
-
-	JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
-	JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *v * f ) );
-	*rval = OBJECT_TO_JSVAL( vector3d );
-
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::divide( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
-{
-	GET_VECTOR_AND_FLOAT;
-
-	JSObject* vector3d = JS_NewObject( g_ScriptingHost.getContext(), &JSI_Vector3D::JSI_class, NULL, NULL );
-	JS_SetPrivate( g_ScriptingHost.getContext(), vector3d, new JSI_Vector3D::Vector3D_Info( *v * ( 1.0f / f ) ) );
-	*rval = OBJECT_TO_JSVAL( vector3d );
-
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::dot( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
-{
-	GET_VECTORS;
-
-	*rval = ToJSVal( a->Dot( *b ) );
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::cross( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
-{
-	GET_VECTORS;
-
-	*rval = ToJSVal( a->Cross( *b ) );
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::length( JSContext* cx, JSObject* obj,
-	uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
-{
-	CVector3D* v = GetVector( cx, obj );
-	if(!v)
-		return( JS_TRUE );
-
-	*rval = ToJSVal( v->Length() );
-	return( JS_TRUE );
-}
-
-JSBool JSI_Vector3D::normalize( JSContext* cx, JSObject* obj,
-	uintN UNUSED(argc), jsval* UNUSED(argv), jsval* rval )
-{
-	CVector3D* v = GetVector( cx, obj );
-	if(!v)
-		return( JS_TRUE );
-
-	CVector3D r( v->X, v->Y, v->Z );
-	r.Normalize();
-
-	*rval = ToJSVal( r );
-	return( JS_TRUE );
-}
diff -r 6b3ac7e864ba source/maths/scripting/JSInterface_Vector3D.h
--- a/source/maths/scripting/JSInterface_Vector3D.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/maths/scripting/JSInterface_Vector3D.h	Thu Nov 04 14:52:01 2010 +0000
@@ -36,42 +36,31 @@
 		component_y,
 		component_z
 	};
-	JSBool toString( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool add( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool subtract( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool negate( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool scale( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool divide( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool dot( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool cross( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool length( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-	JSBool normalize( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	JSBool toString(JSContext* cx, uintN argc, jsval* vp);
 
 	struct Vector3D_Info
 	{
 		IPropertyOwner* owner;
-		void ( IPropertyOwner::*updateFn )();
-		void ( IPropertyOwner::*freshenFn )();
+		void (IPropertyOwner::*updateFn)();
+		void (IPropertyOwner::*freshenFn)();
 		CVector3D* vector;
 		Vector3D_Info();
-		Vector3D_Info( float x, float y, float z );
-		Vector3D_Info( const CVector3D& copy );
-		Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner );
-		Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner, void (IPropertyOwner::*_updateFn)(void) );
-		Vector3D_Info( CVector3D* attach, IPropertyOwner* _owner, void (IPropertyOwner::*_updateFn)(void), void (IPropertyOwner::*_freshenFn)(void) );
+		Vector3D_Info(float x, float y, float z);
+		Vector3D_Info(const CVector3D& copy);
+		Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner);
+		Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner, void(IPropertyOwner::*_updateFn)(void));
+		Vector3D_Info(CVector3D* attach, IPropertyOwner* _owner, void(IPropertyOwner::*_updateFn)(void), void(IPropertyOwner::*_freshenFn)(void));
 		~Vector3D_Info();
 	};
 	extern JSClass JSI_class;
 	extern JSPropertySpec JSI_props[];
 	extern JSFunctionSpec JSI_methods[];
 
-	JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-    JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-	void finalize( JSContext* cx, JSObject* obj );
-	JSBool construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
-    void init();
+	JSBool getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
+	JSBool setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
+	void finalize(JSContext* cx, JSObject* obj);
+	JSBool construct(JSContext* cx, uintN argc, jsval* vp);
+	void init();
 }
 
 #endif
-
-
diff -r 6b3ac7e864ba source/ps/ConfigDB.cpp
--- a/source/ps/ConfigDB.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/ps/ConfigDB.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -35,34 +35,42 @@
 
 namespace ConfigNamespace_JS
 {
-	JSBool GetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
+	JSBool GetProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
+{
+		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
+		if (cfgNs < 0 || cfgNs >= CFG_LAST)
+			return JS_FALSE;
+
+		jsval idval;
+		if (!JS_IdToValue(cx, id, &idval))
+			return JS_FALSE;
+
+		CStr propName = g_ScriptingHost.ValueToString(idval);
+		CConfigValue *val = g_ConfigDB.GetValue(cfgNs, propName);
+		if (val)
+		{
+			JSString *js_str = JS_NewStringCopyN(cx, val->m_String.c_str(), val->m_String.size());
+			*vp = STRING_TO_JSVAL(js_str);
+		}
+		return JS_TRUE;
+	}
+
+	JSBool SetProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp)
 	{
 		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
 		if (cfgNs < 0 || cfgNs >= CFG_LAST)
 			return JS_FALSE;
 
-		CStr propName = g_ScriptingHost.ValueToString(id);
-		CConfigValue *val=g_ConfigDB.GetValue(cfgNs, propName);
-		if (val)
-		{
-			JSString *js_str=JS_NewStringCopyN(cx, val->m_String.c_str(), val->m_String.size());
-			*vp = STRING_TO_JSVAL(js_str);
-		}
-		return JS_TRUE;
-	}
-
-	JSBool SetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
-	{
-		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
-		if (cfgNs < 0 || cfgNs >= CFG_LAST)
+		jsval idval;
+		if (!JS_IdToValue(cx, id, &idval))
 			return JS_FALSE;
 
-		CStr propName = g_ScriptingHost.ValueToString(id);
-		CConfigValue *val=g_ConfigDB.CreateValue(cfgNs, propName);
+		CStr propName = g_ScriptingHost.ValueToString(idval);
+		CConfigValue *val = g_ConfigDB.CreateValue(cfgNs, propName);
 		char *str;
 		if (JS_ConvertArguments(cx, 1, vp, "s", &str))
 		{
-			val->m_String=str;
+			val->m_String = str;
 			return JS_TRUE;
 		}
 		else
@@ -77,13 +85,12 @@
 		JS_ConvertStub, JS_FinalizeStub
 	};
 
-	JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* UNUSED(argv), jsval* rval )
+	JSBool Construct(JSContext* cx, uintN argc, jsval* vp)
 	{
-		if (argc != 0)
-			return JS_FALSE;
+		UNUSED2(argc);
 
-		JSObject *newObj=JS_NewObject(cx, &Class, NULL, obj);
-		*rval=OBJECT_TO_JSVAL(newObj);
+		JSObject *newObj = JS_NewObject(cx, &Class, NULL, NULL);
+		JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObj));
 		return JS_TRUE;
 	}
 
@@ -92,9 +99,9 @@
 		JS_SetPrivate(cx, obj, (void *)((uintptr_t)cfgNs << 1)); // JS requires bottom bit = 0
 	}
 
-	JSBool WriteFile( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
+	JSBool WriteFile(JSContext* cx, uintN argc, jsval* vp)
 	{
-		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
+		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, JS_THIS_OBJECT(cx, vp));
 		if (cfgNs < 0 || cfgNs >= CFG_LAST)
 			return JS_FALSE;
 		
@@ -103,44 +110,45 @@
 
 		JSBool useVFS;
 		char *path;
-		if (JS_ConvertArguments(cx, 2, argv, "bs", &useVFS, &path))
+		if (JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "bs", &useVFS, &path))
 		{
-			JSBool res=g_ConfigDB.WriteFile(cfgNs, useVFS?true:false, CStrW(path));
-			*rval = BOOLEAN_TO_JSVAL(res);
+			JSBool res = g_ConfigDB.WriteFile(cfgNs, useVFS ? true : false, CStrW(path));
+			JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(res));
 			return JS_TRUE;
 		}
 		else
 			return JS_FALSE;
 	}
 
-	JSBool Reload( JSContext* cx, JSObject* obj, uintN argc, jsval* UNUSED(argv), jsval* rval )
+	JSBool Reload(JSContext* cx, uintN argc, jsval* vp)
 	{
 		if (argc != 0)
 			return JS_FALSE;
 
-		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
+		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, JS_THIS_OBJECT(cx, vp));
 		if (cfgNs < 0 || cfgNs >= CFG_LAST)
 			return JS_FALSE;
 
-		JSBool ret=g_ConfigDB.Reload(cfgNs);
-		*rval = BOOLEAN_TO_JSVAL(ret);
+		JSBool ret = g_ConfigDB.Reload(cfgNs);
+		JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(ret));
 		return JS_TRUE;
 	}
 
-	JSBool SetFile( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval) )
+	JSBool SetFile(JSContext* cx, uintN argc, jsval* vp)
 	{
 		if (argc != 0)
 			return JS_FALSE;
 
-		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, obj);
+		EConfigNamespace cfgNs = GET_NS_PRIVATE(cx, JS_THIS_OBJECT(cx, vp));
 		if (cfgNs < 0 || cfgNs >= CFG_LAST)
 			return JS_FALSE;
 
 		JSBool useVFS;
 		char *path;
-		if (JS_ConvertArguments(cx, 2, argv, "bs", &useVFS, &path))
+		if (JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "bs", &useVFS, &path))
 		{
-			g_ConfigDB.SetConfigFile(cfgNs, useVFS?true:false, CStrW(path));
+			g_ConfigDB.SetConfigFile(cfgNs, useVFS ? true : false, CStrW(path));
+			JS_SET_RVAL(cx, vp, JSVAL_VOID);
 			return JS_TRUE;
 		}
 		else
@@ -148,9 +156,9 @@
 	}
 
 	JSFunctionSpec Funcs[] = {
-		{ "writeFile", WriteFile, 2, 0, 0},
-		{ "reload", Reload, 0, 0, 0},
-		{ "setFile", SetFile, 2, 0, 0},
+		{ "writeFile", WriteFile, 2, 0 },
+		{ "reload", Reload, 0, 0 },
+		{ "setFile", SetFile, 2, 0 },
 		{0}
 	};
 };
@@ -173,13 +181,12 @@
 		{0}
 	};
 
-	JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* UNUSED(argv), jsval* rval )
+	JSBool Construct(JSContext* cx, uintN argc, jsval* vp)
 	{
-		if (argc != 0)
-			return JS_FALSE;
+		UNUSED2(argc);
 
-		JSObject *newObj=JS_NewObject(cx, &Class, NULL, obj);
-		*rval=OBJECT_TO_JSVAL(newObj);
+		JSObject *newObj = JS_NewObject(cx, &Class, NULL, NULL);
+		JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObj));
 
 		int flags=JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT;
 #define cfg_ns(_propname, _enum) STMT (\
@@ -204,15 +211,16 @@
 {
 	g_ScriptingHost.DefineCustomObjectType(&ConfigDB_JS::Class, ConfigDB_JS::Construct, 0, ConfigDB_JS::Props, ConfigDB_JS::Funcs, NULL, NULL);
 	g_ScriptingHost.DefineCustomObjectType(&ConfigNamespace_JS::Class, ConfigNamespace_JS::Construct, 0, NULL, ConfigNamespace_JS::Funcs, NULL, NULL);
-	JSObject *js_ConfigDB=g_ScriptingHost.CreateCustomObject("ConfigDB");
+	JSObject *js_ConfigDB = g_ScriptingHost.CreateCustomObject("ConfigDB");
 	g_ScriptingHost.SetGlobal("g_ConfigDB", OBJECT_TO_JSVAL(js_ConfigDB));
 }
 
 CConfigValue *CConfigDB::GetValue(EConfigNamespace ns, const CStr& name)
 {
-	CConfigValueSet* values = GetValues( ns, name );
-	if( !values ) return( NULL );
-	return &( (*values)[0] );
+	CConfigValueSet* values = GetValues(ns, name);
+	if (!values)
+		return (NULL);
+	return &((*values)[0]);
 }
 
 CConfigValueSet *CConfigDB::GetValues(EConfigNamespace ns, const CStr& name)
@@ -223,18 +231,18 @@
 		return NULL;
 	}
 
-	TConfigMap::iterator it = m_Map[CFG_COMMAND].find( name );
-	if( it != m_Map[CFG_COMMAND].end() )
-		return &( it->second );
+	TConfigMap::iterator it = m_Map[CFG_COMMAND].find(name);
+	if (it != m_Map[CFG_COMMAND].end())
+		return &(it->second);
 
-	for( int search_ns = ns; search_ns >= 0; search_ns-- )
+	for (int search_ns = ns; search_ns >= 0; search_ns--)
 	{
 		TConfigMap::iterator it = m_Map[search_ns].find(name);
 		if (it != m_Map[search_ns].end())
-			return &( it->second );
+			return &(it->second);
 	}
 
-	return( NULL );
+	return NULL;
 }	
 
 std::vector<std::pair<CStr, CConfigValueSet> > CConfigDB::GetValuesWithPrefix(EConfigNamespace ns, const CStr& prefix)
diff -r 6b3ac7e864ba source/ps/GameSetup/GameSetup.cpp
--- a/source/ps/GameSetup/GameSetup.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/ps/GameSetup/GameSetup.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -76,9 +76,6 @@
 
 #include "maths/scripting/JSInterface_Vector3D.h"
 
-#include "graphics/scripting/JSInterface_Camera.h"
-#include "graphics/scripting/JSInterface_LightEnv.h"
-
 #include "ps/scripting/JSInterface_Console.h"
 
 #include "gui/GUI.h"
@@ -304,8 +301,6 @@
 	JSI_Vector3D::init();
 
 	// graphics
-	JSI_Camera::init();
-	JSI_LightEnv::init();
 	CGameView::ScriptingInit();
 
 	// renderer
diff -r 6b3ac7e864ba source/ps/scripting/JSInterface_Console.cpp
--- a/source/ps/scripting/JSInterface_Console.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/ps/scripting/JSInterface_Console.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2009 Wildfire Games.
+/* Copyright (C) 2010 Wildfire Games.
  * This file is part of 0 A.D.
  *
  * 0 A.D. is free software: you can redistribute it and/or modify
@@ -40,81 +40,85 @@
 
 JSFunctionSpec JSI_Console::JSI_methods[] = 
 {
-	{ "write", JSI_Console::writeConsole, 1, 0, 0 },
+	{ "write", JSI_Console::writeConsole, 1, 0 },
 	{ 0 },
 };
 
-JSBool JSI_Console::getProperty( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval id, jsval* vp )
+JSBool JSI_Console::getProperty(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid id, jsval* vp)
 {
-	if( !JSVAL_IS_INT( id ) )
-		return( JS_TRUE );
+	if (!JSID_IS_INT(id))
+		return JS_TRUE;
 
-	int i = JSVAL_TO_INT( id );
+	int i = JSID_TO_INT(id);
 
-	switch( i )
+	switch (i)
 	{
 	case console_visible:
-		*vp = BOOLEAN_TO_JSVAL( g_Console->IsActive() ); return( JS_TRUE );
+		*vp = BOOLEAN_TO_JSVAL(g_Console->IsActive());
+		return JS_TRUE;
 	default:
-		*vp = JSVAL_NULL; return( JS_TRUE );
-	}	
+		*vp = JSVAL_NULL;
+		return JS_TRUE;
+	}
 }
 
-JSBool JSI_Console::setProperty( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval id, jsval* vp )
+JSBool JSI_Console::setProperty(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid id, jsval* vp)
 {
-	if( !JSVAL_IS_INT( id ) )
-		return( JS_TRUE );
+	if (!JSID_IS_INT(id))
+		return JS_TRUE;
 
-	int i = JSVAL_TO_INT( id );
+	int i = JSID_TO_INT(id);
 
-	switch( i )
+	switch (i)
 	{
 	case console_visible:
 		try
 		{
-			g_Console->SetVisible( ToPrimitive<bool>( *vp ) );
-			return( JS_TRUE );
+			g_Console->SetVisible(ToPrimitive<bool> (*vp));
+			return JS_TRUE;
 		}
-		catch( PSERROR_Scripting_ConversionFailed )
+		catch (PSERROR_Scripting_ConversionFailed )
 		{
-			return( JS_TRUE );
+			return JS_TRUE;
 		}
 	default:
-		return( JS_TRUE );
-	}	
+		return JS_TRUE;
+	}
 }
 
 void JSI_Console::init()
 {
-	g_ScriptingHost.DefineCustomObjectType( &JSI_class, NULL, 0, JSI_props, JSI_methods, NULL, NULL );
+	g_ScriptingHost.DefineCustomObjectType(&JSI_class, NULL, 0, JSI_props, JSI_methods, NULL, NULL);
 }
 
-JSBool JSI_Console::getConsole( JSContext* cx, JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
+JSBool JSI_Console::getConsole(JSContext* cx, JSObject* UNUSED(obj), jsid UNUSED(id), jsval* vp)
 {
-	JSObject* console = JS_NewObject( cx, &JSI_Console::JSI_class, NULL, NULL );
-	*vp = OBJECT_TO_JSVAL( console );
-	return( JS_TRUE );
+	JSObject* console = JS_NewObject(cx, &JSI_Console::JSI_class, NULL, NULL);
+	*vp = OBJECT_TO_JSVAL(console);
+	return JS_TRUE;
 }
 
-JSBool JSI_Console::writeConsole( JSContext* UNUSED(context), JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* UNUSED(rval) )
+JSBool JSI_Console::writeConsole(JSContext* cx, uintN argc, jsval* vp)
 {
-	debug_assert( argc >= 1 );
+	UNUSED2(cx);
+
 	CStrW output;
-	for( unsigned int i = 0; i < argc; i++ )
+	for (uintN i = 0; i < argc; i++)
 	{
 		try
 		{
-			CStrW arg = g_ScriptingHost.ValueToUCString( argv[i] );
+			CStrW arg = g_ScriptingHost.ValueToUCString(JS_ARGV(cx, vp)[i]);
 			output += arg;
 		}
-		catch( PSERROR_Scripting_ConversionFailed )
+		catch (PSERROR_Scripting_ConversionFailed )
 		{
 		}
 	}
 
 	// TODO: What if the console has been destroyed already?
 	if (g_Console)
-		g_Console->InsertMessage( L"%ls", output.c_str() );
+		g_Console->InsertMessage(L"%ls", output.c_str());
 
-	return( JS_TRUE );
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
+	return JS_TRUE;
 }
diff -r 6b3ac7e864ba source/ps/scripting/JSInterface_Console.h
--- a/source/ps/scripting/JSInterface_Console.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/ps/scripting/JSInterface_Console.h	Thu Nov 04 14:52:01 2010 +0000
@@ -34,14 +34,14 @@
 	extern JSPropertySpec JSI_props[];
 	extern JSFunctionSpec JSI_methods[];
 
-	JSBool getProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
-	JSBool setProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp );
+	JSBool getProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
+	JSBool setProperty(JSContext* cx, JSObject* obj, jsid id, jsval* vp);
 
-	JSBool getConsole( JSContext* context, JSObject* obj, jsval id, jsval* vp );
+	JSBool getConsole(JSContext* context, JSObject* obj, jsid id, jsval* vp);
 
 	void init();
 
-	JSBool writeConsole( JSContext* context, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	JSBool writeConsole(JSContext* cx, uintN argc, jsval* vp);
 }
 
 #endif
diff -r 6b3ac7e864ba source/ps/scripting/JSInterface_VFS.cpp
--- a/source/ps/scripting/JSInterface_VFS.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/ps/scripting/JSInterface_VFS.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -29,15 +29,15 @@
 // shared error handling code
 #define JS_CHECK_FILE_ERR(err)\
 	/* this is liable to happen often, so don't complain */\
-	if(err == ERR::VFS_FILE_NOT_FOUND)\
+	if (err == ERR::VFS_FILE_NOT_FOUND)\
 	{\
-		*rval = JSVAL_NULL;\
-		return( JS_TRUE );\
+		JS_SET_RVAL(cx, vp, JSVAL_NULL);\
+		return JS_TRUE;\
 	}\
 	/* unknown failure. we return an error (akin to an exception in JS) that
 	   stops the script to make sure this error is noticed. */\
-	else if(err < 0)\
-		return( JS_FALSE );\
+	else if (err < 0)\
+		return JS_FALSE;\
 	/* else: success */
 
 
@@ -54,13 +54,13 @@
 		: cx(cx_)
 	{
 		filename_array = JS_NewArrayObject(cx, 0, NULL);
-		JS_AddRoot(cx, &filename_array);
+		JS_AddObjectRoot(cx, &filename_array);
 		cur_idx = 0;
 	}
 
 	~BuildDirEntListState()
 	{
-		JS_RemoveRoot(cx, &filename_array);
+		JS_RemoveObjectRoot(cx, &filename_array);
 	}
 };
 
@@ -85,44 +85,45 @@
 //
 // note: full pathnames of each file/subdirectory are returned,
 // ready for use as a "filename" for the other functions.
-JSBool JSI_VFS::BuildDirEntList( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
+JSBool JSI_VFS::BuildDirEntList(JSContext* cx, uintN argc, jsval* vp)
 {
 	//
 	// get arguments
 	//
 
-	debug_assert( argc >= 1 );
+	JSU_REQUIRE_MIN_PARAMS(1);
+
 	CStr path;
-	if( !ToPrimitive<CStr>( cx, argv[0], path ) )
-		return( JS_FALSE );
+	if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], path))
+		return JS_FALSE;
 
 	CStrW filter_str = L"";
-	if(argc >= 2)
+	if (argc >= 2)
 	{
-		if( !ToPrimitive<CStrW>( cx, argv[1], filter_str ) )
-			return( JS_FALSE );
+		if (!ToPrimitive<CStrW> (cx, JS_ARGV(cx, vp)[1], filter_str))
+			return JS_FALSE;
 	}
 	// convert to const wchar_t*; if there's no filter, pass 0 for speed
 	// (interpreted as: "accept all files without comparing").
 	const wchar_t* filter = 0;
-	if(!filter_str.empty())
+	if (!filter_str.empty())
 		filter = filter_str.c_str();
 
 	bool recursive = false;
-	if(argc >= 3)
+	if (argc >= 3)
 	{
-		if( !ToPrimitive<bool>( cx, argv[2], recursive ) )
-			return( JS_FALSE );
+		if (!ToPrimitive<bool> (cx, JS_ARGV(cx, vp)[2], recursive))
+			return JS_FALSE;
 	}
-	int flags = recursive? fs_util::DIR_RECURSIVE : 0;
+	int flags = recursive ? fs_util::DIR_RECURSIVE : 0;
 
 
 	// build array in the callback function
 	BuildDirEntListState state(cx);
 	fs_util::ForEachFile(g_VFS, CStrW(path), BuildDirEntListCB, (uintptr_t)&state, filter, flags);
 
-	*rval = OBJECT_TO_JSVAL( state.filename_array );
-	return( JS_TRUE );
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(state.filename_array));
+	return JS_TRUE;
 }
 
 
@@ -130,19 +131,20 @@
 //
 // mtime = getFileMTime(filename);
 //   filename: VFS filename (may include path)
-JSBool JSI_VFS::GetFileMTime( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
+JSBool JSI_VFS::GetFileMTime(JSContext* cx, uintN argc, jsval* vp)
 {
-	debug_assert( argc >= 1 );
+	JSU_REQUIRE_MIN_PARAMS(1);
+
 	CStr filename;
-	if( !ToPrimitive<CStr>( cx, argv[0], filename ) )
-		return( JS_FALSE );
+	if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], filename))
+		return JS_FALSE;
 
 	FileInfo fileInfo;
 	LibError err = g_VFS->GetFileInfo(CStrW(filename), &fileInfo);
-	JS_CHECK_FILE_ERR( err );
+	JS_CHECK_FILE_ERR(err);
 
-	*rval = ToJSVal( (double)fileInfo.MTime() );
-	return( JS_TRUE );
+	JS_SET_RVAL(cx, vp, ToJSVal((double)fileInfo.MTime()));
+	return JS_TRUE;
 }
 
 
@@ -150,19 +152,20 @@
 //
 // size = getFileSize(filename);
 //   filename: VFS filename (may include path)
-JSBool JSI_VFS::GetFileSize( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
+JSBool JSI_VFS::GetFileSize(JSContext* cx, uintN argc, jsval* vp)
 {
-	debug_assert( argc >= 1 );
+	JSU_REQUIRE_MIN_PARAMS(1);
+
 	CStr filename;
-	if( !ToPrimitive<CStr>( cx, argv[0], filename ) )
-		return( JS_FALSE );
+	if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], filename))
+		return JS_FALSE;
 
 	FileInfo fileInfo;
 	LibError err = g_VFS->GetFileInfo(CStrW(filename), &fileInfo);
 	JS_CHECK_FILE_ERR(err);
 
-	*rval = ToJSVal( (unsigned)fileInfo.Size() );
-	return( JS_TRUE );
+	JS_SET_RVAL(cx, vp, ToJSVal( (unsigned)fileInfo.Size() ));
+	return JS_TRUE;
 }
 
 
@@ -170,25 +173,27 @@
 //
 // contents = readFile(filename);
 //   filename: VFS filename (may include path)
-JSBool JSI_VFS::ReadFile( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
+JSBool JSI_VFS::ReadFile(JSContext* cx, uintN argc, jsval* vp)
 {
-	debug_assert( argc >= 1 );
+	JSU_REQUIRE_MIN_PARAMS(1);
+
 	CStr filename;
-	if( !ToPrimitive<CStr>( cx, argv[0], filename ) )
-		return( JS_FALSE );
+	if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], filename))
+		return JS_FALSE;
 
-	shared_ptr<u8> buf; size_t size;
-	LibError err = g_VFS->LoadFile( CStrW(filename), buf, size );
+	shared_ptr<u8> buf;
+	size_t size;
+	LibError err = g_VFS->LoadFile(CStrW(filename), buf, size);
 	JS_CHECK_FILE_ERR( err );
 
-	CStr contents( (const char*)buf.get(), size );
+	CStr contents((const char*)buf.get(), size);
 
 	// Fix CRLF line endings. (This function will only ever be used on text files.)
 	contents.Replace("\r\n", "\n");
 
 	// Decode as UTF-8
-	*rval = ToJSVal( contents.FromUTF8() );
-	return( JS_TRUE );
+	JS_SET_RVAL(cx, vp, ToJSVal( contents.FromUTF8() ));
+	return JS_TRUE;
 }
 
 
@@ -196,22 +201,24 @@
 //
 // lines = readFileLines(filename);
 //   filename: VFS filename (may include path)
-JSBool JSI_VFS::ReadFileLines( JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval )
+JSBool JSI_VFS::ReadFileLines(JSContext* cx, uintN argc, jsval* vp)
 {
-	debug_assert( argc >= 1 );
+	JSU_REQUIRE_MIN_PARAMS(1);
+
 	CStr filename;
-	if( !ToPrimitive<CStr>( cx, argv[0], filename ) )
-		return( JS_FALSE );
+	if (!ToPrimitive<CStr> (cx, JS_ARGV(cx, vp)[0], filename))
+		return (JS_FALSE);
 
 	//
 	// read file
 	//
 
-	shared_ptr<u8> buf; size_t size;
-	LibError err = g_VFS->LoadFile( CStrW(filename), buf, size );
+	shared_ptr<u8> buf;
+	size_t size;
+	LibError err = g_VFS->LoadFile(CStrW(filename), buf, size);
 	JS_CHECK_FILE_ERR( err );
 
-	CStr contents( (const char*)buf.get(), size );
+	CStr contents((const char*)buf.get(), size);
 
 	// Fix CRLF line endings. (This function will only ever be used on text files.)
 	contents.Replace("\r\n", "\n");
@@ -220,32 +227,33 @@
 	// split into array of strings (one per line)
 	//
 
-	std::stringstream ss( contents );
+	std::stringstream ss(contents);
 
-	JSObject* line_array = JS_NewArrayObject( cx, 0, NULL );
-	JS_AddRoot(cx, &line_array);
+	JSObject* line_array = JS_NewArrayObject(cx, 0, NULL);
 
 	std::string line;
 	int cur_line = 0;
-	while( std::getline( ss, line ) )
+	while (std::getline(ss, line))
 	{
 		// Decode each line as UTF-8
-		jsval val = ToJSVal( CStr( line ).FromUTF8() );
-		JS_SetElement( cx, line_array, cur_line++, &val );
+		jsval val = ToJSVal(CStr(line).FromUTF8());
+		JS_SetElement(cx, line_array, cur_line++, &val);
 	}
 
-	JS_RemoveRoot(cx, &line_array);
-
-	*rval = OBJECT_TO_JSVAL( line_array );
-	return( JS_TRUE );
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL( line_array ));
+	return JS_TRUE ;
 }
 
 
 // vfs_optimizer
 
-JSBool JSI_VFS::ArchiveBuilderCancel(JSContext* UNUSED(cx), JSObject* UNUSED(obj), uintN argc, jsval* UNUSED(argv), jsval* UNUSED(rval) )
+JSBool JSI_VFS::ArchiveBuilderCancel(JSContext* cx, uintN argc, jsval* vp)
 {
-	debug_assert( argc == 0 );
+	UNUSED2(cx);
+	UNUSED2(argc);
+
 //	vfs_opt_auto_build_cancel();
-	return( JS_TRUE );
+
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
+	return JS_TRUE;
 }
diff -r 6b3ac7e864ba source/ps/scripting/JSInterface_VFS.h
--- a/source/ps/scripting/JSInterface_VFS.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/ps/scripting/JSInterface_VFS.h	Thu Nov 04 14:52:01 2010 +0000
@@ -38,36 +38,36 @@
 	//
 	// note: full pathnames of each file/subdirectory are returned,
 	// ready for use as a "filename" for the other functions.
-	JSBool BuildDirEntList( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	JSBool BuildDirEntList(JSContext* cx, uintN argc, jsval* vp);
 
 	// Return time [seconds since 1970] of the last modification to the specified file.
 	//
 	// mtime = getFileMTime(filename);
 	//   filename: VFS filename (may include path)
-	JSBool GetFileMTime( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	JSBool GetFileMTime(JSContext* cx, uintN argc, jsval* vp);
 
 	// Return current size of file.
 	//
 	// size = getFileSize(filename);
 	//   filename: VFS filename (may include path)
-	JSBool GetFileSize( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	JSBool GetFileSize(JSContext* cx, uintN argc, jsval* vp);
 
 	// Return file contents in a string.
 	//
 	// contents = readFile(filename);
 	//   filename: VFS filename (may include path)
-	JSBool ReadFile( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	JSBool ReadFile(JSContext* cx, uintN argc, jsval* vp);
 
 	// Return file contents as an array of lines.
 	//
 	// lines = readFileLines(filename);
 	//   filename: VFS filename (may include path)
-	JSBool ReadFileLines( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	JSBool ReadFileLines(JSContext* cx, uintN argc, jsval* vp);
 
 	// Abort the current archive build operation (no-op if not currently active).
 	//
 	// archiveBuilderCancel();
-	JSBool ArchiveBuilderCancel(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	JSBool ArchiveBuilderCancel(JSContext* cx, uintN argc, jsval* vp);
 }
 
 #endif
diff -r 6b3ac7e864ba source/scripting/JSConversions.cpp
--- a/source/scripting/JSConversions.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scripting/JSConversions.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -180,12 +180,16 @@
 
 template<> jsval ToJSVal<double>( const double& Native )
 {
-	return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), Native ) ) );
+	jsval val = JSVAL_VOID;
+	JS_NewNumberValue( g_ScriptingHost.getContext(), Native, &val );
+	return val;
 }
 
 template<> jsval ToJSVal<double>( double& Native )
 {
-	return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), Native ) ) );
+	jsval val = JSVAL_VOID;
+	JS_NewNumberValue( g_ScriptingHost.getContext(), Native, &val );
+	return val;
 }
 
 template<> bool ToPrimitive<double>( JSContext* cx, jsval v, double& Storage )
@@ -200,12 +204,16 @@
 
 template<> jsval ToJSVal<float>( const float& Native )
 {
-	return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), Native ) ) );
+	jsval val = JSVAL_VOID;
+	JS_NewNumberValue( g_ScriptingHost.getContext(), Native, &val );
+	return val;
 }
 
 template<> jsval ToJSVal<float>( float& Native )
 {
-	return( DOUBLE_TO_JSVAL( JS_NewDouble( g_ScriptingHost.getContext(), Native ) ) );
+	jsval val = JSVAL_VOID;
+	JS_NewNumberValue( g_ScriptingHost.getContext(), Native, &val );
+	return val;
 }
 
 template<> bool ToPrimitive<float>( JSContext* cx, jsval v, float& Storage )
@@ -304,18 +312,12 @@
 	stringParser.InputTaskType( "string", "_$value_" );
 	CParserLine result;
 	result.ParseString( stringParser, CStr(Native) );
-	bool boolResult; int intResult; float floatResult;
+	bool boolResult;
+	float floatResult;
 
 	if( result.GetArgFloat( 0, floatResult ) )
-	{
-		if( floatResult == floor( floatResult ) )
-		{
-			intResult = (int)floatResult;
-			if( INT_FITS_IN_JSVAL( intResult ) )
-				return( ToJSVal( intResult ) );
-		}
 		return( ToJSVal( floatResult ) );
-	}
+
 	if( result.GetArgBool( 0, boolResult ) )
 		return( BOOLEAN_TO_JSVAL( boolResult ) ); 
 	
diff -r 6b3ac7e864ba source/scripting/JSUtil.cpp
--- a/source/scripting/JSUtil.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scripting/JSUtil.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -19,12 +19,12 @@
 
 #include "SpiderMonkey.h"
 
-jsval jsu_report_param_error(JSContext* cx, jsval* rval)
+JSBool jsu_report_param_error(JSContext* cx, jsval* vp)
 {
 	JS_ReportError(cx, "Invalid parameter(s) or count");
 
-	if(rval)
-		*rval = JSVAL_NULL;
+	if (vp)
+		JS_SET_RVAL(cx, vp, JSVAL_NULL);
 
 	// yes, we had an error, but returning JS_FALSE would cause SpiderMonkey
 	// to abort. that would be hard to debug.
diff -r 6b3ac7e864ba source/scripting/JSUtil.h
--- a/source/scripting/JSUtil.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scripting/JSUtil.h	Thu Nov 04 14:52:01 2010 +0000
@@ -17,7 +17,7 @@
 
 // included from SpiderMonkey.h
 
-extern jsval jsu_report_param_error(JSContext* cx, jsval* rval);
+extern JSBool jsu_report_param_error(JSContext* cx, jsval* vp);
 
 
 // consistent argc checking for normal function wrappers: reports an
@@ -25,24 +25,23 @@
 // .. require exact number (most common case)
 #define JSU_REQUIRE_PARAMS(exact_number)\
 	if(argc != exact_number)\
-		return jsu_report_param_error(cx, rval);
+		return jsu_report_param_error(cx, vp);
 // .. require 0 params (avoids L4 warning "unused argv param")
 #define JSU_REQUIRE_NO_PARAMS()\
-	UNUSED2(argv);\
 	if(argc != 0)\
-		return jsu_report_param_error(cx, rval);
+		return jsu_report_param_error(cx, vp);
 // .. require a certain range (e.g. due to optional params)
 #define JSU_REQUIRE_PARAM_RANGE(min_number, max_number)\
 	if(!(min_number <= argc && argc <= max_number))\
-		return jsu_report_param_error(cx, rval);
+		return jsu_report_param_error(cx, vp);
 // .. require at most a certain count
 #define JSU_REQUIRE_MAX_PARAMS(max_number)\
 	if(argc > max_number)\
-		return jsu_report_param_error(cx, rval);
+		return jsu_report_param_error(cx, vp);
 // .. require at least a certain count (rarely needed)
 #define JSU_REQUIRE_MIN_PARAMS(min_number)\
 	if(argc < min_number)\
-		return jsu_report_param_error(cx, rval);
+		return jsu_report_param_error(cx, vp);
 
 // same as JSU_REQUIRE_PARAMS, but used from C++ functions that are
 // a bit further removed from SpiderMonkey, i.e. return a
diff -r 6b3ac7e864ba source/scripting/ScriptGlue.cpp
--- a/source/scripting/ScriptGlue.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scripting/ScriptGlue.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -31,8 +31,6 @@
 #include "graphics/MapWriter.h"
 #include "graphics/Unit.h"
 #include "graphics/UnitManager.h"
-#include "graphics/scripting/JSInterface_Camera.h"
-#include "graphics/scripting/JSInterface_LightEnv.h"
 #include "gui/GUIManager.h"
 #include "gui/IGUIObject.h"
 #include "lib/frequency_filter.h"
@@ -109,24 +107,26 @@
 	js_timer_clients[0].sum.SetToZero();
 }
 
-JSBool StartJsTimer(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
+JSBool StartJsTimer(JSContext* cx, uintN argc, jsval* vp)
 {
 	ONCE(InitJsTimers());
 
 	JSU_REQUIRE_PARAMS(1);
-	size_t slot = ToPrimitive<size_t>(argv[0]);
+	size_t slot = ToPrimitive<size_t>(JS_ARGV(cx, vp)[0]);
 	if (slot >= MAX_JS_TIMERS)
 		return JS_FALSE;
 
 	js_start_times[slot].SetFromTimer();
+
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
 	return JS_TRUE;
 }
 
 
-JSBool StopJsTimer(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
+JSBool StopJsTimer(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_PARAMS(1);
-	size_t slot = ToPrimitive<size_t>(argv[0]);
+	size_t slot = ToPrimitive<size_t>(JS_ARGV(cx, vp)[0]);
 	if (slot >= MAX_JS_TIMERS)
 		return JS_FALSE;
 
@@ -135,6 +135,8 @@
 	now.Subtract(js_timer_overhead);
 	BillingPolicy_Default()(&js_timer_clients[slot], js_start_times[slot], now);
 	js_start_times[slot].SetToZero();
+
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
 	return JS_TRUE;
 }
 
@@ -146,11 +148,13 @@
 // Immediately ends the current game (if any).
 // params:
 // returns:
-JSBool EndGame(JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval)
+JSBool EndGame(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_NO_PARAMS();
 
 	EndGame();
+
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
 	return JS_TRUE;
 }
 
@@ -164,13 +168,13 @@
 // notes:
 // - This value is recalculated once a frame. We take special care to
 //   filter it, so it is both accurate and free of jitter.
-JSBool GetFps( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
+JSBool GetFps(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_NO_PARAMS();
 	int freq = 0;
 	if (g_frequencyFilter)
 		freq = g_frequencyFilter->StableFrequency();
-	*rval = INT_TO_JSVAL(freq);
+	JS_SET_RVAL(cx, vp, INT_TO_JSVAL(freq));
 	return JS_TRUE;
 }
 
@@ -181,28 +185,13 @@
 // notes:
 // - Exit happens after the current main loop iteration ends
 //   (since this only sets a flag telling it to end)
-JSBool ExitProgram( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
+JSBool ExitProgram(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_NO_PARAMS();
 
 	kill_mainloop();
-	return JS_TRUE;
-}
 
-
-// Write an indication of total video RAM to console.
-// params:
-// returns:
-// notes:
-// - May not be supported on all platforms.
-// - Only a rough approximation; do not base low-level decisions
-//   ("should I allocate one more texture?") on this.
-JSBool WriteVideoMemToConsole( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
-{
-	JSU_REQUIRE_NO_PARAMS();
-
-	const SDL_VideoInfo* videoInfo = SDL_GetVideoInfo();
-	g_Console->InsertMessage(L"VRAM: total %d", videoInfo->video_mem);
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
 	return JS_TRUE;
 }
 
@@ -212,38 +201,27 @@
 // returns:
 // notes:
 // - Cursors are stored in "art\textures\cursors"
-JSBool SetCursor( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
+JSBool SetCursor(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_PARAMS(1);
-	g_CursorName = g_ScriptingHost.ValueToUCString(argv[0]);
+	g_CursorName = g_ScriptingHost.ValueToUCString(JS_ARGV(cx, vp)[0]);
+
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
 	return JS_TRUE;
 }
 
-// Change the LOD bias.
-// params: LOD bias [float]
-// returns:
-// notes:
-// - value is as required by GL_TEXTURE_LOD_BIAS.
-// - useful for adjusting image "sharpness" (since it affects which mipmap level is chosen)
-JSBool _LodBias( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
+JSBool GetGUIObjectByName(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_PARAMS(1);
 
-	g_Renderer.SetOptionFloat(CRenderer::OPT_LODBIAS, ToPrimitive<float>(argv[0]));
-	return JS_TRUE;
-}
-
-
-JSBool GetGUIObjectByName(JSContext* cx, JSObject* UNUSED(obj), uintN UNUSED(argc), jsval* argv, jsval* rval)
-{
 	try
 	{
-		CStr name = ToPrimitive<CStr>(cx, argv[0]);
+		CStr name = ToPrimitive<CStr>(cx, JS_ARGV(cx, vp)[0]);
 		IGUIObject* guiObj = g_GUI->FindObjectByName(name);
 		if (guiObj)
-			*rval = OBJECT_TO_JSVAL(guiObj->GetJSObject());
+			JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(guiObj->GetJSObject()));
 		else
-			*rval = JSVAL_NULL;
+			JS_SET_RVAL(cx, vp, JSVAL_NULL);
 		return JS_TRUE;
 	}
 	catch (PSERROR_Scripting&)
@@ -270,14 +248,14 @@
 //   lib/svn_revision.cpp. it is useful to know when attempting to
 //   reproduce bugs (the main EXE and PDB should be temporarily reverted to
 //   that revision so that they match user-submitted crashdumps).
-JSBool GetBuildTimestamp( JSContext* cx, JSObject*, uintN argc, jsval* argv, jsval* rval )
+JSBool GetBuildTimestamp(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_MAX_PARAMS(1);
 
 	char buf[200];
 
 	// see function documentation
-	const int mode = argc? JSVAL_TO_INT(argv[0]) : -1;
+	const int mode = argc? JSVAL_TO_INT(JS_ARGV(cx, vp)[0]) : -1;
 	switch(mode)
 	{
 	case -1:
@@ -294,7 +272,7 @@
 		break;
 	}
 
-	*rval = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buf));
+	JS_SET_RVAL(cx, vp, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, buf)));
 	return JS_TRUE;
 }
 
@@ -311,8 +289,11 @@
 }
 #endif
 
-JSBool DumpHeaps(JSContext* UNUSED(cx), JSObject* UNUSED(globalObject), uintN UNUSED(argc), jsval* UNUSED(argv), jsval* UNUSED(rval) )
+JSBool DumpHeaps(JSContext* cx, uintN argc, jsval* vp)
 {
+	UNUSED2(cx);
+	UNUSED2(argc);
+
 #ifdef DEBUG
 	static int i = 0;
 
@@ -325,47 +306,50 @@
 #else
 	debug_warn(L"DumpHeaps only available in DEBUG mode");
 #endif
+
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
 	return JS_TRUE;
 }
 
 //-----------------------------------------------------------------------------
 
 // Is the game paused?
-JSBool IsPaused( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
+JSBool IsPaused(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_NO_PARAMS();
 
-	if( !g_Game )
+	if (!g_Game)
 	{
-		JS_ReportError( cx, "Game is not started" );
+		JS_ReportError(cx, "Game is not started");
 		return JS_FALSE;
 	}
 
-	*rval = g_Game->m_Paused ? JSVAL_TRUE : JSVAL_FALSE;
-	return JS_TRUE ;
+	JS_SET_RVAL(cx, vp, g_Game->m_Paused ? JSVAL_TRUE : JSVAL_FALSE);
+	return JS_TRUE;
 }
 
 // Pause/unpause the game
-JSBool SetPaused( JSContext* cx, JSObject* UNUSED(globalObject), uintN argc, jsval* argv, jsval* rval )
+JSBool SetPaused(JSContext* cx, uintN argc, jsval* vp)
 {
 	JSU_REQUIRE_PARAMS( 1 );
 
-	if( !g_Game )
+	if (!g_Game)
 	{
-		JS_ReportError( cx, "Game is not started" );
+		JS_ReportError(cx, "Game is not started");
 		return JS_FALSE;
 	}
 
 	try
 	{
-		g_Game->m_Paused = ToPrimitive<bool>( argv[0] );
+		g_Game->m_Paused = ToPrimitive<bool> (JS_ARGV(cx, vp)[0]);
 	}
-	catch( PSERROR_Scripting_ConversionFailed )
+	catch (PSERROR_Scripting_ConversionFailed)
 	{
-		JS_ReportError( cx, "Invalid parameter to SetPaused" );
+		JS_ReportError(cx, "Invalid parameter to SetPaused");
 	}
 
-	return  JS_TRUE;
+	JS_SET_RVAL(cx, vp, JSVAL_VOID);
+	return JS_TRUE;
 }
 
 
@@ -381,7 +365,7 @@
 // - Extra (reserved for future use, always zero)
 //
 // we simplify this a bit with a macro:
-#define JS_FUNC(script_name, cpp_function, min_params) { script_name, cpp_function, min_params, 0, 0 },
+#define JS_FUNC(script_name, cpp_function, min_params) { script_name, cpp_function, min_params, 0 },
 
 JSFunctionSpec ScriptFunctionTable[] =
 {
@@ -404,8 +388,6 @@
 	JS_FUNC("exit", ExitProgram, 0)
 	JS_FUNC("isPaused", IsPaused, 0)
 	JS_FUNC("setPaused", SetPaused, 1)
-	JS_FUNC("vmem", WriteVideoMemToConsole, 0)
-	JS_FUNC("_lodBias", _LodBias, 0)
 	JS_FUNC("setCursor", SetCursor, 1)
 	JS_FUNC("getFPS", GetFps, 0)
 	JS_FUNC("getGUIObjectByName", GetGUIObjectByName, 1)
@@ -415,7 +397,7 @@
 	JS_FUNC("dumpHeaps", DumpHeaps, 0)
 
 	// end of table marker
-	{0, 0, 0, 0, 0}
+	{0}
 };
 #undef JS_FUNC
 
@@ -424,23 +406,22 @@
 // property accessors
 //-----------------------------------------------------------------------------
 
-JSBool GetGameView( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
+JSBool GetGameView(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid UNUSED(id), jsval* vp)
 {
 	if (g_Game)
-		*vp = OBJECT_TO_JSVAL( g_Game->GetView()->GetScript() );
+		*vp = OBJECT_TO_JSVAL(g_Game->GetView()->GetScript());
 	else
 		*vp = JSVAL_NULL;
-	return( JS_TRUE );
+	return JS_TRUE;
 }
 
-
-JSBool GetRenderer( JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsval UNUSED(id), jsval* vp )
+JSBool GetRenderer(JSContext* UNUSED(cx), JSObject* UNUSED(obj), jsid UNUSED(id), jsval* vp)
 {
 	if (CRenderer::IsInitialised())
-		*vp = OBJECT_TO_JSVAL( g_Renderer.GetScript() );
+		*vp = OBJECT_TO_JSVAL(g_Renderer.GetScript());
 	else
 		*vp = JSVAL_NULL;
-	return( JS_TRUE );
+	return JS_TRUE;
 }
 
 
@@ -455,9 +436,7 @@
 
 JSPropertySpec ScriptGlobalTable[] =
 {
-	{ "camera"     , GLOBAL_CAMERA,      JSPROP_PERMANENT, JSI_Camera::getCamera, JSI_Camera::setCamera },
 	{ "console"    , GLOBAL_CONSOLE,     JSPROP_PERMANENT|JSPROP_READONLY, JSI_Console::getConsole, 0 },
-	{ "lightenv"   , GLOBAL_LIGHTENV,    JSPROP_PERMANENT, JSI_LightEnv::getLightEnv, JSI_LightEnv::setLightEnv },
 	{ "gameView"   , 0,                  JSPROP_PERMANENT|JSPROP_READONLY, GetGameView, 0 },
 	{ "renderer"   , 0,                  JSPROP_PERMANENT|JSPROP_READONLY, GetRenderer, 0 },
 
diff -r 6b3ac7e864ba source/scripting/ScriptableObject.h
--- a/source/scripting/ScriptableObject.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scripting/ScriptableObject.h	Thu Nov 04 14:52:01 2010 +0000
@@ -155,12 +155,12 @@
 	void Root()
 	{
 		if( JSVAL_IS_GCTHING( m_Data ) )
-			JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_Data, "ScriptableObjectProperty" );
+			JS_AddNamedValueRoot( g_ScriptingHost.GetContext(), &m_Data, "ScriptableObjectProperty" );
 	}
 	void Uproot()
 	{
 		if( JSVAL_IS_GCTHING( m_Data ))
-			JS_RemoveRoot( g_ScriptingHost.GetContext(), (void*)&m_Data );
+			JS_RemoveValueRoot( g_ScriptingHost.GetContext(), &m_Data );
 	}
 	jsval Get( JSContext* UNUSED(cx), IJSObject* UNUSED(object))
 	{
@@ -179,14 +179,14 @@
 template<typename T, bool ReadOnly, typename RType, RType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )> class CNativeFunction
 {
 public:
-	static JSBool JSFunction( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval )
+	static JSBool JSFunction( JSContext* cx, uintN argc, jsval* vp )
 	{
-		T* Native = ToNative<T>( cx, obj );
+		T* Native = ToNative<T>( cx, JS_THIS_OBJECT( cx, vp ) );
 		if( !Native )
-			return( JS_TRUE );
+			return( JS_FALSE );
 
-		*rval = ToJSVal<RType>( (Native->*NativeFunction)( cx, argc, argv ) );
-
+		jsval rval = ToJSVal<RType>( (Native->*NativeFunction)( cx, argc, JS_ARGV(cx, vp) ) );
+		JS_SET_RVAL( cx, vp, rval );
 		return( JS_TRUE );
 	}
 };
@@ -196,14 +196,15 @@
 class CNativeFunction<T, ReadOnly, void, NativeFunction>
 {
 public:
-	static JSBool JSFunction( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* UNUSED(rval) )
+	static JSBool JSFunction( JSContext* cx, uintN argc, jsval* vp )
 	{
-		T* Native = ToNative<T>( cx, obj );
+		T* Native = ToNative<T>( cx, JS_THIS_OBJECT( cx, vp ) );
 		if( !Native )
-			return( JS_TRUE );
+			return( JS_FALSE );
 
-		(Native->*NativeFunction)( cx, argc, argv );
+		(Native->*NativeFunction)( cx, argc, JS_ARGV(cx, vp) );
 
+		JS_SET_RVAL( cx, vp, JSVAL_VOID );
 		return( JS_TRUE );
 	}
 };
@@ -328,7 +329,7 @@
 	template<typename ReturnType, ReturnType (T::*NativeFunction)( JSContext* cx, uintN argc, jsval* argv )> 
 		static void AddMethod( const char* Name, uintN MinArgs )
 	{
-		JSFunctionSpec FnInfo = { Name, CNativeFunction<T, ReadOnly, ReturnType, NativeFunction>::JSFunction, (uint8)MinArgs, 0, 0 };
+		JSFunctionSpec FnInfo = { Name, CNativeFunction<T, ReadOnly, ReturnType, NativeFunction>::JSFunction, (uint8)MinArgs, 0 };
 		m_Methods.push_back( FnInfo );
 	}
 	template<typename PropType> static void AddProperty( const CStrW& PropertyName, PropType T::*Native, bool PropReadOnly = ReadOnly )
@@ -373,7 +374,7 @@
 		{
 			m_JS = JS_NewObject( g_ScriptingHost.GetContext(), &JSI_class, NULL, NULL );
 			if( m_EngineOwned )
-				JS_AddNamedRoot( g_ScriptingHost.GetContext(), (void*)&m_JS, JSI_class.name );
+				JS_AddNamedObjectRoot( g_ScriptingHost.GetContext(), &m_JS, JSI_class.name );
 	
 			JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, (T*)this );
 		}
@@ -384,7 +385,7 @@
 		{
 			JS_SetPrivate( g_ScriptingHost.GetContext(), m_JS, NULL );
 			if( m_EngineOwned )
-				JS_RemoveRoot( g_ScriptingHost.GetContext(), &m_JS );
+				JS_RemoveObjectRoot( g_ScriptingHost.GetContext(), &m_JS );
 			m_JS = NULL;
 		}
 	}
@@ -393,26 +394,34 @@
 	// Functions and data that must be provided to JavaScript
 	// 
 private:
-	static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
+	static JSBool JSGetProperty( JSContext* cx, JSObject* obj, jsid id, jsval* vp )
 	{
 		T* Instance = ToNative<T>( cx, obj );
 		if( !Instance )
 			return( JS_TRUE );
 
-		CStrW PropName = g_ScriptingHost.ValueToUCString( id );
+		jsval idval;
+		if( !JS_IdToValue( cx, id, &idval ) )
+			return( JS_FALSE );
+
+		CStrW PropName = g_ScriptingHost.ValueToUCString( idval );
 
 		if( !Instance->GetProperty( cx, PropName, vp ) )
 			return( JS_TRUE );
 		
 		return( JS_TRUE );
 	}
-	static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsval id, jsval* vp )
+	static JSBool JSSetProperty( JSContext* cx, JSObject* obj, jsid id, jsval* vp )
 	{
 		T* Instance = ToNative<T>( cx, obj );
 		if( !Instance )
 			return( JS_TRUE );
 
-		CStrW PropName = g_ScriptingHost.ValueToUCString( id );
+		jsval idval;
+		if( !JS_IdToValue( cx, id, &idval ) )
+			return( JS_FALSE );
+
+		CStrW PropName = g_ScriptingHost.ValueToUCString( idval );
 
 		Instance->SetProperty( cx, PropName, vp );
 
diff -r 6b3ac7e864ba source/scripting/ScriptingHost.cpp
--- a/source/scripting/ScriptingHost.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scripting/ScriptingHost.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -168,12 +168,10 @@
 
 void ScriptingHost::SetObjectProperty_Double(JSObject* object, const char* propertyName, double value)
 {
-	jsdouble* d = JS_NewDouble(m_Context, value);
-	if (! d)
+	jsval v;
+	if (! JS_NewNumberValue(m_Context, value, &v))
 		throw PSERROR_Scripting_ConversionFailed();
 
-	jsval v = DOUBLE_TO_JSVAL(d);
-
 	if (! JS_SetProperty(m_Context, object, propertyName, &v))
 		throw PSERROR_Scripting_ConversionFailed();
 }
diff -r 6b3ac7e864ba source/scripting/SpiderMonkey.h
--- a/source/scripting/SpiderMonkey.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scripting/SpiderMonkey.h	Thu Nov 04 14:52:01 2010 +0000
@@ -45,11 +45,6 @@
 
 #include <js/jsapi.h>
 
-#ifndef NDEBUG
-// Used by ScriptingHost::jshook_{script,function}
-# include <js/jsdbgapi.h>
-#endif
-
 // include any further required headers here
 
 #include "JSUtil.h"
diff -r 6b3ac7e864ba source/scriptinterface/AutoRooters.cpp
--- a/source/scriptinterface/AutoRooters.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/AutoRooters.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -47,4 +47,15 @@
 	{
 		JS_CALL_VALUE_TRACER(trc, m_Vals[i], "AutoGCRooter val");
 	}
+
+	for (size_t i = 0; i < m_IdArrays.size(); ++i)
+	{
+		for (jsint j = 0; j < m_IdArrays[i]->length; ++j)
+		{
+			jsval val = JSVAL_VOID;
+			JS_IdToValue(m_ScriptInterface.GetContext(), m_IdArrays[i]->vector[j], &val);
+			JS_CALL_VALUE_TRACER(trc, val, "AutoGCRooter id array");
+		}
+	}
+
 }
diff -r 6b3ac7e864ba source/scriptinterface/AutoRooters.h
--- a/source/scriptinterface/AutoRooters.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/AutoRooters.h	Thu Nov 04 14:52:01 2010 +0000
@@ -22,30 +22,6 @@
 
 #include "js/jsapi.h"
 
-// Exception-safety and GC-safety wrapper for JSIdArray
-// (TODO: it'd be nicer to use the existing js::AutoIdArray but currently that
-// requires a load of semi-private SpiderMonkey headers that cause a load of compile warnings)
-class IdArrayWrapper
-{
-	JSContext* m_cx;
-	JSIdArray* m_ida;
-public:
-	IdArrayWrapper(JSContext* cx, JSIdArray* ida) :
-		m_cx(cx), m_ida(ida)
-	{
-		for (jsint i = 0; i < m_ida->length; ++i)
-			if (!JS_AddRoot(m_cx, &m_ida->vector[i]))
-				debug_warn(L"JS_AddRoot failed");
-	}
-	~IdArrayWrapper()
-	{
-		for (jsint i = 0; i < m_ida->length; ++i)
-			if (!JS_RemoveRoot(m_cx, &m_ida->vector[i]))
-				debug_warn(L"JS_RemoveRoot failed");
-		JS_DestroyIdArray(m_cx, m_ida);
-	}
-};
-
 /**
  * Helper for rooting large groups of script values.
  * Construct this object, push values into it, and they will all be rooted until this
@@ -61,6 +37,7 @@
 
 	void Push(JSObject* obj) { m_Objects.push_back(obj); }
 	void Push(jsval val) { m_Vals.push_back(val); }
+	void Push(JSIdArray* ida) { m_IdArrays.push_back(ida); }
 
 	void Trace(JSTracer* trc);
 private:
@@ -69,6 +46,7 @@
 
 	std::vector<JSObject*> m_Objects;
 	std::vector<jsval> m_Vals;
+	std::vector<JSIdArray*> m_IdArrays;
 	// TODO: add vectors of other value types
 };
 
diff -r 6b3ac7e864ba source/scriptinterface/ScriptConversions.cpp
--- a/source/scriptinterface/ScriptConversions.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/ScriptConversions.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -139,13 +139,10 @@
 	return rval;
 }
 
-template<> jsval ScriptInterface::ToJSVal<i32>(JSContext* cx, const i32& val)
+template<> jsval ScriptInterface::ToJSVal<i32>(JSContext* UNUSED(cx), const i32& val)
 {
-	if (INT_FITS_IN_JSVAL(val))
-		return INT_TO_JSVAL(val);
-	jsval rval = JSVAL_VOID;
-	JS_NewNumberValue(cx, val, &rval); // ignore return value
-	return rval;
+	cassert(JSVAL_INT_BITS == 32);
+	return INT_TO_JSVAL(val);
 }
 
 template<> jsval ScriptInterface::ToJSVal<u32>(JSContext* cx, const u32& val)
@@ -201,13 +198,11 @@
 	JSObject* obj = JS_NewArrayObject(cx, 0, NULL);
 	if (!obj)
 		return JSVAL_VOID;
-	JS_AddRoot(cx, &obj);
 	for (size_t i = 0; i < val.size(); ++i)
 	{
 		jsval el = ScriptInterface::ToJSVal<T>(cx, val[i]);
 		JS_SetElement(cx, obj, (jsint)i, &el);
 	}
-	JS_RemoveRoot(cx, &obj);
 	return OBJECT_TO_JSVAL(obj);
 }
 
diff -r 6b3ac7e864ba source/scriptinterface/ScriptInterface.cpp
--- a/source/scriptinterface/ScriptInterface.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/ScriptInterface.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -39,6 +39,8 @@
 const int RUNTIME_SIZE = 16 * 1024 * 1024; // TODO: how much memory is needed?
 const int STACK_CHUNK_SIZE = 8192;
 
+#define signbit(x) ((x) < 0.0 ? true : false) // XXX
+
 #if ENABLE_SCRIPT_PROFILING
 #include "js/jsdbgapi.h"
 #endif
@@ -49,7 +51,7 @@
 {
 	ScriptInterface_impl(const char* nativeScopeName, JSContext* cx);
 	~ScriptInterface_impl();
-	void Register(const char* name, JSFastNative fptr, uintN nargs);
+	void Register(const char* name, JSNative fptr, uintN nargs);
 
 	JSRuntime* m_rt; // NULL if m_cx is shared; non-NULL if we own m_cx
 	JSContext* m_cx;
@@ -286,7 +288,7 @@
 		// Threadsafe SpiderMonkey requires that we have a request before doing anything much
 		JS_BeginRequest(m_cx);
 
-		m_glob = JS_NewObject(m_cx, &global_class, NULL, NULL);
+		m_glob = JS_NewGlobalObject(m_cx, &global_class);
 		ok = JS_InitStandardClasses(m_cx, m_glob);
 
 		JS_DefineProperty(m_cx, m_glob, "global", OBJECT_TO_JSVAL(m_glob), NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
@@ -296,10 +298,10 @@
 	m_nativeScope = JS_DefineObject(m_cx, m_glob, nativeScopeName, NULL, NULL, JSPROP_ENUMERATE | JSPROP_READONLY
 			| JSPROP_PERMANENT);
 
-	JS_DefineFunction(m_cx, m_glob, "print", (JSNative)::print,  0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
-	JS_DefineFunction(m_cx, m_glob, "log",   (JSNative)::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
-	JS_DefineFunction(m_cx, m_glob, "warn",  (JSNative)::warn,   1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
-	JS_DefineFunction(m_cx, m_glob, "error", (JSNative)::error,  1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
+	JS_DefineFunction(m_cx, m_glob, "print", ::print,  0, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
+	JS_DefineFunction(m_cx, m_glob, "log",   ::logmsg, 1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
+	JS_DefineFunction(m_cx, m_glob, "warn",  ::warn,   1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
+	JS_DefineFunction(m_cx, m_glob, "error", ::error,  1, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
 }
 
 ScriptInterface_impl::~ScriptInterface_impl()
@@ -312,9 +314,9 @@
 	}
 }
 
-void ScriptInterface_impl::Register(const char* name, JSFastNative fptr, uintN nargs)
+void ScriptInterface_impl::Register(const char* name, JSNative fptr, uintN nargs)
 {
-	JS_DefineFunction(m_cx, m_nativeScope, name, reinterpret_cast<JSNative>(fptr), nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
+	JS_DefineFunction(m_cx, m_nativeScope, name, fptr, nargs, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
 }
 
 ScriptInterface::ScriptInterface(const char* nativeScopeName, const char* debugName) :
@@ -361,8 +363,8 @@
 		return;
 	}
 
-	JSFunction* random = JS_DefineFunction(m->m_cx, JSVAL_TO_OBJECT(math), "random", (JSNative)Math_random, 0,
-			JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSFUN_FAST_NATIVE);
+	JSFunction* random = JS_DefineFunction(m->m_cx, JSVAL_TO_OBJECT(math), "random", Math_random, 0,
+			JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT);
 	if (!random)
 	{
 		LOGERROR(L"ReplaceNondeterministicFunctions: failed to replace Math.random");
@@ -372,7 +374,7 @@
 	JS_SetReservedSlot(m->m_cx, JS_GetFunctionObject(random), 0, PRIVATE_TO_JSVAL(&rng));
 }
 
-void ScriptInterface::Register(const char* name, JSFastNative fptr, size_t nargs)
+void ScriptInterface::Register(const char* name, JSNative fptr, size_t nargs)
 {
 	m->Register(name, fptr, (uintN)nargs);
 }
@@ -387,16 +389,6 @@
 	return m->m_rt;
 }
 
-bool ScriptInterface::AddRoot(void* ptr, const char* name)
-{
-	return JS_AddNamedRoot(m->m_cx, ptr, name) ? true : false;
-}
-
-bool ScriptInterface::RemoveRoot(void* ptr)
-{
-	return JS_RemoveRoot(m->m_cx, ptr) ? true : false;
-}
-
 AutoGCRooter* ScriptInterface::ReplaceAutoGCRooter(AutoGCRooter* rooter)
 {
 	debug_assert(m->m_rt); // this class must own the runtime, else the rooter won't work
@@ -494,19 +486,14 @@
 	JSObject* obj;
 	if (!JS_ValueToObject(m->m_cx, val, &obj) || obj == NULL)
 		return false;
-	JS_AddRoot(m->m_cx, &obj);
 
 	// Check that the named function actually exists, to avoid ugly JS error reports
 	// when calling an undefined value
 	JSBool found;
 	if (!JS_HasProperty(m->m_cx, obj, name, &found) || !found)
-	{
-		JS_RemoveRoot(m->m_cx, &obj);
 		return false;
-	}
 
 	JSBool ok = JS_CallFunctionName(m->m_cx, obj, name, (uintN)argc, argv, &ret);
-	JS_RemoveRoot(m->m_cx, &obj);
 
 	return ok ? true : false;
 }
@@ -638,10 +625,8 @@
 	if (!func)
 		return false;
 
-	JS_AddRoot(m->m_cx, &func); // TODO: do we need to root this?
 	jsval scriptRval;
 	JSBool ok = JS_CallFunction(m->m_cx, NULL, func, 0, NULL, &scriptRval);
-	JS_RemoveRoot(m->m_cx, &func);
 
 	return ok ? true : false;
 }
@@ -782,7 +767,7 @@
 {
 public:
 	ValueCloner(ScriptInterface& from, ScriptInterface& to) :
-		cxFrom(from.GetContext()), cxTo(to.GetContext()), m_RooterFrom(from), m_RooterTo(to)
+		scriptInterfaceFrom(from), cxFrom(from.GetContext()), cxTo(to.GetContext()), m_RooterFrom(from), m_RooterTo(to)
 	{
 	}
 
@@ -792,7 +777,7 @@
 		if (!JSVAL_IS_GCTHING(val) || JSVAL_IS_NULL(val))
 			return val;
 
-		std::map<jsval, jsval>::iterator it = m_Mapping.find(val);
+		std::map<void*, jsval>::iterator it = m_Mapping.find(JSVAL_TO_GCTHING(val));
 		if (it != m_Mapping.end())
 			return it->second;
 
@@ -811,8 +796,7 @@
 		if (JSVAL_IS_DOUBLE(val))
 		{
 			jsval rval;
-			CLONE_REQUIRE(JS_NewNumberValue(cxTo, *JSVAL_TO_DOUBLE(val), &rval), L"JS_NewNumberValue");
-			m_Mapping[val] = rval;
+			CLONE_REQUIRE(JS_NewNumberValue(cxTo, JSVAL_TO_DOUBLE(val), &rval), L"JS_NewNumberValue");
 			m_RooterTo.Push(rval);
 			return rval;
 		}
@@ -822,7 +806,7 @@
 			JSString* str = JS_NewUCStringCopyN(cxTo, JS_GetStringChars(JSVAL_TO_STRING(val)), JS_GetStringLength(JSVAL_TO_STRING(val)));
 			CLONE_REQUIRE(str, L"JS_NewUCStringCopyN");
 			jsval rval = STRING_TO_JSVAL(str);
-			m_Mapping[val] = rval;
+			m_Mapping[JSVAL_TO_GCTHING(val)] = rval;
 			m_RooterTo.Push(rval);
 			return rval;
 		}
@@ -843,13 +827,14 @@
 			CLONE_REQUIRE(newObj, L"JS_NewObject");
 		}
 
-		m_Mapping[val] = OBJECT_TO_JSVAL(newObj);
+		m_Mapping[JSVAL_TO_GCTHING(val)] = OBJECT_TO_JSVAL(newObj);
 		m_RooterTo.Push(newObj);
 
 		JSIdArray* ida = JS_Enumerate(cxFrom, JSVAL_TO_OBJECT(val));
 		CLONE_REQUIRE(ida, L"JS_Enumerate");
 
-		IdArrayWrapper idaWrapper(cxFrom, ida);
+		AutoGCRooter idaRooter(scriptInterfaceFrom);
+		idaRooter.Push(ida);
 
 		for (jsint i = 0; i < ida->length; ++i)
 		{
@@ -880,9 +865,10 @@
 		return OBJECT_TO_JSVAL(newObj);
 	}
 
+	ScriptInterface& scriptInterfaceFrom;
 	JSContext* cxFrom;
 	JSContext* cxTo;
-	std::map<jsval, jsval> m_Mapping;
+	std::map<void*, jsval> m_Mapping;
 	AutoGCRooter m_RooterFrom;
 	AutoGCRooter m_RooterTo;
 };
diff -r 6b3ac7e864ba source/scriptinterface/ScriptInterface.h
--- a/source/scriptinterface/ScriptInterface.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/ScriptInterface.h	Thu Nov 04 14:52:01 2010 +0000
@@ -223,9 +223,6 @@
 	 */
 	template<typename T> static jsval ToJSVal(JSContext* cx, T const& val);
 
-	bool AddRoot(void* ptr, const char* name);
-	bool RemoveRoot(void* ptr);
-
 	AutoGCRooter* ReplaceAutoGCRooter(AutoGCRooter* rooter);
 
 	/**
@@ -264,7 +261,7 @@
 	static JSClass* GetClass(JSContext* cx, JSObject* obj);
 	static void* GetPrivate(JSContext* cx, JSObject* obj);
 
-	void Register(const char* name, JSFastNative fptr, size_t nargs);
+	void Register(const char* name, JSNative fptr, size_t nargs);
 	std::auto_ptr<ScriptInterface_impl> m;
 
 // The nasty macro/template bits are split into a separate file so you don't have to look at them
@@ -276,10 +273,10 @@
 	//   void RegisterFunction(const char* functionName);
 	//
 	//   template <R, T0..., TR (*fptr) (void* cbdata, T0...)>
-	//   static JSFastNative call;
+	//   static JSNative call;
 	//
 	//   template <R, T0..., JSClass*, TC, TR (TC:*fptr) (T0...)>
-	//   static JSFastNative callMethod;
+	//   static JSNative callMethod;
 	//
 	//   template <dummy, T0...>
 	//   static size_t nargs();
diff -r 6b3ac7e864ba source/scriptinterface/ScriptTypes.h
--- a/source/scriptinterface/ScriptTypes.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/ScriptTypes.h	Thu Nov 04 14:52:01 2010 +0000
@@ -25,8 +25,10 @@
 #endif
 // (we don't support XP_OS2 or XP_BEOS)
 
-#include "js/jspubtd.h"
-#include "js/jsversion.h"
+//#include "js/jspubtd.h"
+//#include "js/jsversion.h"
+
+#include "js/jsapi.h"
 
 #if JS_VERSION != 185
 #error Your compiler is trying to use an incorrect version of the SpiderMonkey library.
diff -r 6b3ac7e864ba source/scriptinterface/ScriptVal.cpp
--- a/source/scriptinterface/ScriptVal.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/ScriptVal.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -24,25 +24,32 @@
 struct Unrooter
 {
 	Unrooter(JSContext* cx) : cx(cx) { }
-	void operator()(jsval* p) { JS_RemoveRoot(cx, p); delete p; }
+	void operator()(jsval* p) { JS_RemoveValueRoot(cx, p); delete p; }
 	JSContext* cx;
 };
 
 CScriptValRooted::CScriptValRooted(JSContext* cx, jsval val)
 {
 	jsval* p = new jsval(val);
-	JS_AddNamedRoot(cx, p, "CScriptValRooted");
+	JS_AddNamedValueRoot(cx, p, "CScriptValRooted");
 	m_Val = boost::shared_ptr<jsval>(p, Unrooter(cx));
 }
 
 CScriptValRooted::CScriptValRooted(JSContext* cx, CScriptVal val)
 {
 	jsval* p = new jsval(val.get());
-	JS_AddNamedRoot(cx, p, "CScriptValRooted");
+	JS_AddNamedValueRoot(cx, p, "CScriptValRooted");
 	m_Val = boost::shared_ptr<jsval>(p, Unrooter(cx));
 }
 
-jsval CScriptValRooted::get() const
+const jsval& CScriptValRooted::get() const
+{
+	if (!m_Val)
+		return JSVAL_VOID;
+	return *m_Val;
+}
+
+jsval& CScriptValRooted::get()
 {
 	if (!m_Val)
 		return JSVAL_VOID;
diff -r 6b3ac7e864ba source/scriptinterface/ScriptVal.h
--- a/source/scriptinterface/ScriptVal.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/ScriptVal.h	Thu Nov 04 14:52:01 2010 +0000
@@ -29,10 +29,10 @@
 class CScriptVal
 {
 public:
-	CScriptVal() : m_Val(0) { }
+	CScriptVal() : m_Val(JSVAL_VOID) { }
 	CScriptVal(jsval val) : m_Val(val) { }
 
-	jsval get() const { return m_Val; }
+	const jsval& get() const { return m_Val; }
 
 private:
 	jsval m_Val;
@@ -45,7 +45,8 @@
 	CScriptValRooted(JSContext* cx, jsval val);
 	CScriptValRooted(JSContext* cx, CScriptVal val);
 
-	jsval get() const;
+	const jsval& get() const;
+	jsval& get();
 
 	bool undefined() const;
 
diff -r 6b3ac7e864ba source/scriptinterface/tests/test_ScriptConversions.h
--- a/source/scriptinterface/tests/test_ScriptConversions.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/tests/test_ScriptConversions.h	Thu Nov 04 14:52:01 2010 +0000
@@ -34,7 +34,6 @@
 		JSContext* cx = script.GetContext();
 
 		jsval v1 = ScriptInterface::ToJSVal(cx, value);
-		JS_AddRoot(cx, &v1);
 
 		// We want to convert values to strings, but can't just call toSource() on them
 		// since they might not be objects. So just use uneval.
@@ -42,8 +41,6 @@
 		TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalObject(cx)), "uneval", CScriptVal(v1), source));
 
 		TS_ASSERT_STR_EQUALS(source, expected);
-
-		JS_RemoveRoot(cx, &v1);
 	}
 
 	template <typename T>
@@ -53,7 +50,6 @@
 		JSContext* cx = script.GetContext();
 
 		jsval v1 = ScriptInterface::ToJSVal(cx, value);
-		JS_AddRoot(cx, &v1);
 
 		std::string source;
 		TS_ASSERT(script.CallFunction(OBJECT_TO_JSVAL(JS_GetGlobalObject(cx)), "uneval", CScriptVal(v1), source));
@@ -64,8 +60,6 @@
 		T v2 = T();
 		TS_ASSERT(ScriptInterface::FromJSVal(script.GetContext(), v1, v2));
 		TS_ASSERT_EQUALS(value, v2);
-
-		JS_RemoveRoot(cx, &v1);
 	}
 
 public:
@@ -132,18 +126,16 @@
 
 		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 0)));
 
-		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 1073741822))); // JSVAL_INT_MAX-1
-		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 1073741823))); // JSVAL_INT_MAX
-		TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal<i32>(cx, 1073741824))); // JSVAL_INT_MAX+1
-		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, -1073741823))); // JSVAL_INT_MIN+1
-		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, -1073741824))); // JSVAL_INT_MIN
-		TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal<i32>(cx, -1073741825))); // JSVAL_INT_MIN-1
+		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 2147483646))); // JSVAL_INT_MAX-1
+		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, 2147483647))); // JSVAL_INT_MAX
+		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, -2147483647))); // JSVAL_INT_MIN+1
+		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<i32>(cx, -2147483648))); // JSVAL_INT_MIN
 
 		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 0)));
 
-		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 1073741822))); // JSVAL_INT_MAX-1
-		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 1073741823))); // JSVAL_INT_MAX
-		TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal<u32>(cx, 1073741824))); // JSVAL_INT_MAX+1
+		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 2147483646))); // JSVAL_INT_MAX-1
+		TS_ASSERT(JSVAL_IS_INT(ScriptInterface::ToJSVal<u32>(cx, 2147483647))); // JSVAL_INT_MAX
+		TS_ASSERT(JSVAL_IS_DOUBLE(ScriptInterface::ToJSVal<u32>(cx, 2147483648))); // JSVAL_INT_MAX+1
 	}
 
 	void test_nonfinite()
diff -r 6b3ac7e864ba source/scriptinterface/tests/test_ScriptInterface.h
--- a/source/scriptinterface/tests/test_ScriptInterface.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/scriptinterface/tests/test_ScriptInterface.h	Thu Nov 04 14:52:01 2010 +0000
@@ -136,7 +136,7 @@
 		TS_ASSERT(script.Eval(input.c_str(), val));
 
 		std::string stringified = script.StringifyJSON(val.get());
-		TS_ASSERT_STR_EQUALS(stringified, "{\n  \"x\":1,\n  \"z\":[2,\n    \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n  ],\n  \"y\":true\n}");
+		TS_ASSERT_STR_EQUALS(stringified, "{\n  \"x\": 1,\n  \"z\": [\n    2,\n    \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n  ],\n  \"y\": true\n}");
 
 		val = script.ParseJSON(stringified);
 		TS_ASSERT_WSTR_EQUALS(script.ToString(val.get()), L"({x:1, z:[2, \"3\\u263A\\uFFFD\"], y:true})");
diff -r 6b3ac7e864ba source/simulation2/scripting/EngineScriptConversions.cpp
--- a/source/simulation2/scripting/EngineScriptConversions.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/scripting/EngineScriptConversions.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -37,7 +37,7 @@
 
 	// If this is a scripted component, just return the JS object directly
 	jsval instance = val->GetJSInstance();
-	if (instance)
+	if (!JSVAL_IS_NULL(instance))
 		return instance;
 
 	// Otherwise we need to construct a wrapper object
diff -r 6b3ac7e864ba source/simulation2/scripting/ScriptComponent.cpp
--- a/source/simulation2/scripting/ScriptComponent.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/scripting/ScriptComponent.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -23,30 +23,22 @@
 #include "simulation2/serialization/IDeserializer.h"
 
 CComponentTypeScript::CComponentTypeScript(ScriptInterface& scriptInterface, jsval instance) :
-	m_ScriptInterface(scriptInterface), m_Instance(instance)
+	m_ScriptInterface(scriptInterface), m_Instance(CScriptValRooted(scriptInterface.GetContext(), instance))
 {
-	debug_assert(instance);
-	m_ScriptInterface.AddRoot(&m_Instance, "CComponentTypeScript.m_Instance");
-
 	// Cache the property detection for efficiency
-	m_HasCustomSerialize = m_ScriptInterface.HasProperty(m_Instance, "Serialize");
-}
-
-CComponentTypeScript::~CComponentTypeScript()
-{
-	m_ScriptInterface.RemoveRoot(&m_Instance);
+	m_HasCustomSerialize = m_ScriptInterface.HasProperty(m_Instance.get(), "Serialize");
 }
 
 void CComponentTypeScript::Init(const CSimContext& UNUSED(context), const CParamNode& paramNode, entity_id_t ent)
 {
-	m_ScriptInterface.SetProperty(m_Instance, "entity", (int)ent, true);
-	m_ScriptInterface.SetProperty(m_Instance, "template", paramNode, true);
-	m_ScriptInterface.CallFunctionVoid(m_Instance, "Init");
+	m_ScriptInterface.SetProperty(m_Instance.get(), "entity", (int)ent, true);
+	m_ScriptInterface.SetProperty(m_Instance.get(), "template", paramNode, true);
+	m_ScriptInterface.CallFunctionVoid(m_Instance.get(), "Init");
 }
 
 void CComponentTypeScript::Deinit(const CSimContext& UNUSED(context))
 {
-	m_ScriptInterface.CallFunctionVoid(m_Instance, "Deinit");
+	m_ScriptInterface.CallFunctionVoid(m_Instance.get(), "Deinit");
 }
 
 void CComponentTypeScript::HandleMessage(const CSimContext& UNUSED(context), const CMessage& msg, bool global)
@@ -55,7 +47,7 @@
 
 	CScriptVal msgVal = msg.ToJSValCached(m_ScriptInterface);
 
-	if (!m_ScriptInterface.CallFunctionVoid(m_Instance, name, msgVal))
+	if (!m_ScriptInterface.CallFunctionVoid(m_Instance.get(), name, msgVal))
 		LOGERROR(L"Script message handler %hs failed", name);
 }
 
@@ -66,13 +58,13 @@
 	if (m_HasCustomSerialize)
 	{
 		CScriptValRooted val;
-		if (!m_ScriptInterface.CallFunction(m_Instance, "Serialize", val))
+		if (!m_ScriptInterface.CallFunction(m_Instance.get(), "Serialize", val))
 			LOGERROR(L"Script Serialize call failed");
 		serialize.ScriptVal("object", val);
 	}
 	else
 	{
-		serialize.ScriptVal("object", m_Instance);
+		serialize.ScriptVal("object", m_Instance.get());
 	}
 }
 
@@ -82,8 +74,8 @@
 
 	// Use ScriptObjectAppend so we don't lose the carefully-constructed
 	// prototype/parent of this object
-	deserialize.ScriptObjectAppend("object", m_Instance);
+	deserialize.ScriptObjectAppend("object", m_Instance.get());
 
-	m_ScriptInterface.SetProperty(m_Instance, "entity", (int)ent, true);
-	m_ScriptInterface.SetProperty(m_Instance, "template", paramNode, true);
+	m_ScriptInterface.SetProperty(m_Instance.get(), "entity", (int)ent, true);
+	m_ScriptInterface.SetProperty(m_Instance.get(), "template", paramNode, true);
 }
diff -r 6b3ac7e864ba source/simulation2/scripting/ScriptComponent.h
--- a/source/simulation2/scripting/ScriptComponent.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/scripting/ScriptComponent.h	Thu Nov 04 14:52:01 2010 +0000
@@ -35,9 +35,8 @@
 {
 public:
 	CComponentTypeScript(ScriptInterface& scriptInterface, jsval instance);
-	~CComponentTypeScript();
 
-	jsval GetInstance() const { return m_Instance; }
+	jsval GetInstance() const { return m_Instance.get(); }
 
 	void Init(const CSimContext& context, const CParamNode& paramNode, entity_id_t ent);
 	void Deinit(const CSimContext& context);
@@ -58,7 +57,7 @@
 	R Call(const char* funcname  BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \
 	{ \
 		R ret; \
-		if (m_ScriptInterface.CallFunction(m_Instance, funcname  BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \
+		if (m_ScriptInterface.CallFunction(m_Instance.get(), funcname  BOOST_PP_ENUM_TRAILING_PARAMS(i, a), ret)) \
 			return ret; \
 		LOGERROR(L"Error calling component script function %hs", funcname); \
 		return R(); \
@@ -66,7 +65,7 @@
 	BOOST_PP_IF(i, template<, ) BOOST_PP_ENUM_PARAMS(i, typename T) BOOST_PP_IF(i, >, ) \
 	void CallVoid(const char* funcname  BOOST_PP_ENUM_TRAILING_BINARY_PARAMS(i, const T, &a)) \
 	{ \
-		if (m_ScriptInterface.CallFunctionVoid(m_Instance, funcname  BOOST_PP_ENUM_TRAILING_PARAMS(i, a))) \
+		if (m_ScriptInterface.CallFunctionVoid(m_Instance.get(), funcname  BOOST_PP_ENUM_TRAILING_PARAMS(i, a))) \
 			return; \
 		LOGERROR(L"Error calling component script function %hs", funcname); \
 	}
@@ -75,7 +74,7 @@
 
 private:
 	ScriptInterface& m_ScriptInterface;
-	jsval m_Instance;
+	CScriptValRooted m_Instance;
 	bool m_HasCustomSerialize;
 
 	NONCOPYABLE(CComponentTypeScript);
diff -r 6b3ac7e864ba source/simulation2/serialization/BinarySerializer.cpp
--- a/source/simulation2/serialization/BinarySerializer.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/serialization/BinarySerializer.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -32,7 +32,7 @@
 # pragma warning(disable:4800)	// forcing value to bool 'true' or 'false' (performance warning)
 #endif
 
-#include "js/jsobj.h"
+//#include "js/jsobj.h"
 
 #if MSC_VERSION
 # pragma warning(pop)
@@ -100,43 +100,18 @@
 
 		// Find all properties (ordered by insertion time)
 
-		// JS_Enumerate is a bit slow (lots of memory allocation), so do the enumeration manually
-		// (based on the code from JS_Enumerate, using the probably less stable JSObject API):
-		//
-		// Correction: Actually array_enumerate returns an incorrect num_properties so we can't
-		// trust it and have to iterate over all ids before we know how many there are, so
-		// actually this probably isn't any faster than JS_Enumerate. Also it's less compatible
-		// with future JSAPI updates. This probably wasn't a great idea.
-
 		// (Note that we don't do any rooting, because we assume nothing is going to trigger GC.
 		// I'm not absolute certain that's necessarily a valid assumption.)
 
-		jsval iter_state, num_properties;
-		if (!obj->enumerate(cx, JSENUMERATE_INIT, &iter_state, &num_properties))
-			throw PSERROR_Serialize_ScriptError("enumerate INIT failed");
-		debug_assert(JSVAL_IS_INT(num_properties));
-		debug_assert(JSVAL_TO_INT(num_properties) >= 0);
+		JSIdArray* ida = JS_Enumerate(cx, obj);
+		if (!ida)
+			throw PSERROR_Serialize_ScriptError("JS_Enumerate failed");
 
-		std::vector<jsid> ids;
-		ids.reserve(JSVAL_TO_INT(num_properties));
+		m_Serializer.NumberU32_Unbounded("num props", (uint32_t)ida->length);
 
-		while (true)
+		for (jsint i = 0; i < ida->length; ++i)
 		{
-			jsval id;
-			if (!obj->enumerate(cx, JSENUMERATE_NEXT, &iter_state, &id))
-				throw PSERROR_Serialize_ScriptError("enumerate NEXT failed");
-
-			if (JSVAL_IS_NULL(iter_state))
-				break;
-
-			ids.push_back(id);
-		}
-
-		m_Serializer.NumberU32_Unbounded("num props", (uint32_t)ids.size());
-
-		for (size_t i = 0; i < ids.size(); ++i)
-		{
-			jsval id = ids[i];
+			jsid id = ida->vector[i];
 
 			jsval idval, propval;
 
@@ -183,8 +158,7 @@
 		{
 			debug_assert(JSVAL_IS_DOUBLE(val));
 			m_Serializer.NumberU8_Unbounded("type", SCRIPT_TYPE_DOUBLE);
-			jsdouble* dbl = JSVAL_TO_DOUBLE(val);
-			m_Serializer.NumberDouble_Unbounded("value", *dbl);
+			m_Serializer.NumberDouble_Unbounded("value", JSVAL_TO_DOUBLE(val));
 		}
 		break;
 	}
diff -r 6b3ac7e864ba source/simulation2/serialization/StdDeserializer.cpp
--- a/source/simulation2/serialization/StdDeserializer.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/serialization/StdDeserializer.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -46,7 +46,7 @@
 {
 	std::pair<std::map<u32, JSObject*>::iterator, bool> it = m_ScriptBackrefs.insert(std::make_pair((u32)m_ScriptBackrefs.size()+1, obj));
 	debug_assert(it.second);
-	if (!JS_AddRoot(m_ScriptInterface.GetContext(), (void*)&it.first->second))
+	if (!JS_AddObjectRoot(m_ScriptInterface.GetContext(), &it.first->second))
 		throw PSERROR_Deserialize_ScriptError("JS_AddRoot failed");
 }
 
@@ -63,7 +63,7 @@
 	std::map<u32, JSObject*>::iterator it = m_ScriptBackrefs.begin();
 	for (; it != m_ScriptBackrefs.end(); ++it)
 	{
-		if (!JS_RemoveRoot(m_ScriptInterface.GetContext(), (void*)&it->second))
+		if (!JS_RemoveObjectRoot(m_ScriptInterface.GetContext(), &it->second))
 			throw PSERROR_Deserialize_ScriptError("JS_RemoveRoot failed");
 	}
 	m_ScriptBackrefs.clear();
diff -r 6b3ac7e864ba source/simulation2/system/ComponentManager.cpp
--- a/source/simulation2/system/ComponentManager.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/system/ComponentManager.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -100,12 +100,6 @@
 CComponentManager::~CComponentManager()
 {
 	ResetState();
-
-	// Release GC roots
-	std::map<ComponentTypeId, ComponentType>::iterator it = m_ComponentTypesById.begin();
-	for (; it != m_ComponentTypesById.end(); ++it)
-		if (it->second.type == CT_Script)
-			m_ScriptInterface.RemoveRoot(&it->second.ctor);
 }
 
 void CComponentManager::LoadComponentTypes()
@@ -194,10 +188,7 @@
 			}
 		}
 
-		// Clean up the old component type
-		componentManager->m_ScriptInterface.RemoveRoot(&componentManager->m_ComponentTypesById[cid].ctor);
-
-		// Remove its old message subscriptions
+		// Remove the old component type's message subscriptions
 		std::map<MessageTypeId, std::vector<ComponentTypeId> >::iterator it;
 		for (it = componentManager->m_LocalMessageSubscriptions.begin(); it != componentManager->m_LocalMessageSubscriptions.end(); ++it)
 		{
@@ -228,15 +219,19 @@
 	}
 
 	// Construct a new ComponentType, using the wrapper's alloc functions
-	ComponentType ct = { CT_Script, iid, ctWrapper.alloc, ctWrapper.dealloc, cname, schema, ctor.get() };
+	ComponentType ct = {
+		CT_Script,
+		iid,
+		ctWrapper.alloc,
+		ctWrapper.dealloc,
+		cname,
+		schema,
+		CScriptValRooted(componentManager->m_ScriptInterface.GetContext(), ctor)
+	};
 	componentManager->m_ComponentTypesById[cid] = ct;
 
 	componentManager->m_CurrentComponent = cid; // needed by Subscribe
 
-	// Stop the ctor getting GCed
-	componentManager->m_ScriptInterface.AddRoot(&componentManager->m_ComponentTypesById[cid].ctor, "ComponentType ctor");
-	// TODO: check carefully that roots will never get leaked etc
-
 
 	// Find all the ctor prototype's On* methods, and subscribe to the appropriate messages:
 
@@ -285,7 +280,7 @@
 		for (; eit != comps.end(); ++eit)
 		{
 			jsval instance = eit->second->GetJSInstance();
-			if (instance)
+			if (!JSVAL_IS_NULL(instance))
 				componentManager->m_ScriptInterface.SetPrototype(instance, proto.get());
 		}
 	}
@@ -458,7 +453,7 @@
 void CComponentManager::RegisterComponentType(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc, DeallocFunc dealloc,
 		const char* name, const std::string& schema)
 {
-	ComponentType c = { CT_Native, iid, alloc, dealloc, name, schema, 0 };
+	ComponentType c = { CT_Native, iid, alloc, dealloc, name, schema, CScriptValRooted() };
 	m_ComponentTypesById.insert(std::make_pair(cid, c));
 	m_ComponentTypeIdsByName[name] = cid;
 }
@@ -466,7 +461,7 @@
 void CComponentManager::RegisterComponentTypeScriptWrapper(InterfaceId iid, ComponentTypeId cid, AllocFunc alloc,
 		DeallocFunc dealloc, const char* name, const std::string& schema)
 {
-	ComponentType c = { CT_ScriptWrapper, iid, alloc, dealloc, name, schema, 0 };
+	ComponentType c = { CT_ScriptWrapper, iid, alloc, dealloc, name, schema, CScriptValRooted() };
 	m_ComponentTypesById.insert(std::make_pair(cid, c));
 	m_ComponentTypeIdsByName[name] = cid;
 	// TODO: merge with RegisterComponentType
@@ -584,11 +579,11 @@
 	std::map<entity_id_t, IComponent*>& emap2 = m_ComponentsByTypeId[cid];
 
 	// If this is a scripted component, construct the appropriate JS object first
-	jsval obj = 0;
+	jsval obj = JSVAL_NULL;
 	if (ct.type == CT_Script)
 	{
-		obj = m_ScriptInterface.CallConstructor(ct.ctor);
-		if (!obj)
+		obj = m_ScriptInterface.CallConstructor(ct.ctor.get());
+		if (JSVAL_IS_VOID(obj))
 		{
 			LOGERROR(L"Script component constructor failed");
 			return NULL;
diff -r 6b3ac7e864ba source/simulation2/system/ComponentManager.h
--- a/source/simulation2/system/ComponentManager.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/system/ComponentManager.h	Thu Nov 04 14:52:01 2010 +0000
@@ -66,7 +66,7 @@
 		DeallocFunc dealloc;
 		std::string name;
 		std::string schema; // RelaxNG fragment
-		jsval ctor; // only valid if type == CT_Script
+		CScriptValRooted ctor; // only valid if type == CT_Script
 	};
 
 public:
diff -r 6b3ac7e864ba source/simulation2/system/IComponent.cpp
--- a/source/simulation2/system/IComponent.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/system/IComponent.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -40,5 +40,5 @@
 
 jsval IComponent::GetJSInstance() const
 {
-	return 0;
+	return JSVAL_NULL;
 }
diff -r 6b3ac7e864ba source/simulation2/system/InterfaceScripted.h
--- a/source/simulation2/system/InterfaceScripted.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/system/InterfaceScripted.h	Thu Nov 04 14:52:01 2010 +0000
@@ -45,38 +45,38 @@
 
 #define DEFINE_INTERFACE_METHOD_0(scriptname, rettype, classname, methodname) \
 	{ scriptname, \
-		reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, &class_##classname, classname, &classname::methodname>)), \
+		ScriptInterface::callMethod<rettype, &class_##classname, classname, &classname::methodname>, \
 		0, \
-		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
+		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
 
 #define DEFINE_INTERFACE_METHOD_1(scriptname, rettype, classname, methodname, arg1) \
 	{ scriptname, \
-		reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, &class_##classname, classname, &classname::methodname>)), \
+		ScriptInterface::callMethod<rettype, arg1, &class_##classname, classname, &classname::methodname>, \
 		1, \
-		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
+		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
 
 #define DEFINE_INTERFACE_METHOD_2(scriptname, rettype, classname, methodname, arg1, arg2) \
 	{ scriptname, \
-		reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, arg2, &class_##classname, classname, &classname::methodname>)), \
+		ScriptInterface::callMethod<rettype, arg1, arg2, &class_##classname, classname, &classname::methodname>, \
 		2, \
-		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
+		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
 
 #define DEFINE_INTERFACE_METHOD_3(scriptname, rettype, classname, methodname, arg1, arg2, arg3) \
 	{ scriptname, \
-		reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, arg2, arg3, &class_##classname, classname, &classname::methodname>)), \
+		ScriptInterface::callMethod<rettype, arg1, arg2, arg3, &class_##classname, classname, &classname::methodname>, \
 		3, \
-		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
+		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
 
 #define DEFINE_INTERFACE_METHOD_4(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4) \
 	{ scriptname, \
-		reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, &class_##classname, classname, &classname::methodname>)), \
+		ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, &class_##classname, classname, &classname::methodname>, \
 		4, \
-		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
+		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
 
 #define DEFINE_INTERFACE_METHOD_5(scriptname, rettype, classname, methodname, arg1, arg2, arg3, arg4, arg5) \
 	{ scriptname, \
-		reinterpret_cast<JSNative>(static_cast<JSFastNative>(ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, &class_##classname, classname, &classname::methodname>)), \
+		ScriptInterface::callMethod<rettype, arg1, arg2, arg3, arg4, arg5, &class_##classname, classname, &classname::methodname>, \
 		5, \
-		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT|JSFUN_FAST_NATIVE, 0 },
+		JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT },
 
 #endif // INCLUDED_INTERFACE_SCRIPTED
diff -r 6b3ac7e864ba source/simulation2/tests/test_ComponentManager.h
--- a/source/simulation2/tests/test_ComponentManager.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/tests/test_ComponentManager.h	Thu Nov 04 14:52:01 2010 +0000
@@ -325,6 +325,7 @@
 	{
 		CSimContext context;
 		CComponentManager man(context);
+		ScriptTestSetup(man.m_ScriptInterface);
 		man.LoadComponentTypes();
 		TS_ASSERT(man.LoadScript(L"simulation/components/test-entityid.js"));
 
@@ -334,10 +335,8 @@
 		man.AddComponent(ent1, man.LookupCID("TestScript1A"), noParam);
 		man.AddComponent(ent2, man.LookupCID("TestScript1A"), noParam);
 
-		TestLogger log;
 		TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent1, IID_Test1))->GetX(), (int)ent1);
 		TS_ASSERT_EQUALS(static_cast<ICmpTest1*> (man.QueryInterface(ent2, IID_Test1))->GetX(), (int)ent2);
-		TS_ASSERT_WSTR_CONTAINS(log.GetOutput(), L"this.entity is read-only");
 	}
 
 	void test_script_QueryInterface()
@@ -632,6 +631,7 @@
 	{
 		CSimContext context;
 		CComponentManager man(context);
+		ScriptTestSetup(man.m_ScriptInterface);
 		man.LoadComponentTypes();
 		TS_ASSERT(man.LoadScript(L"simulation/components/test-serialize.js"));
 
diff -r 6b3ac7e864ba source/simulation2/tests/test_Serializer.h
--- a/source/simulation2/tests/test_Serializer.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/simulation2/tests/test_Serializer.h	Thu Nov 04 14:52:01 2010 +0000
@@ -372,17 +372,17 @@
 		const char stream[] = "\x02" // SCRIPT_TYPE_ARRAY
 					"\x04\0\0\0" // num props
 					"\x01\0\0\0" "0\0" // "0"
-					"\x05" "\x00\0\0\xC0" // SCRIPT_TYPE_INT -1073741824 (JS_INT_MIN)
+					"\x05" "\0\0\0\x80" // SCRIPT_TYPE_INT -2147483648 (JS_INT_MIN)
 					"\x01\0\0\0" "1\0" // "1"
-					"\x06" "\0\0\x40\0\0\0\xD0\xC1" // SCRIPT_TYPE_DOUBLE -1073741825 (JS_INT_MIN-1)
+					"\x06" "\0\0\x20\0\0\0\xE0\xC1" // SCRIPT_TYPE_DOUBLE -2147483649 (JS_INT_MIN-1)
 					"\x01\0\0\0" "2\0" // "2"
-					"\x05" "\xFF\xFF\xFF\x3F" // SCRIPT_TYPE_INT 1073741823
+					"\x05" "\xFF\xFF\xFF\x7F" // SCRIPT_TYPE_INT 2147483647 (JS_INT_MAX)
 					"\x01\0\0\0" "3\0" // "3"
-					"\x06" "\0\0\0\0\0\0\xD0\x41" // SCRIPT_TYPE_DOUBLE 1073741824
+					"\x06" "\0\0\0\0\0\0\xE0\x41" // SCRIPT_TYPE_DOUBLE 2147483648 (JS_INT_MAX+1)
 		;
 
-		helper_script_roundtrip("numbers", "[-1073741824, -1073741825, 1.073741823e+9, 1073741824]",
-				"[-1073741824, -1073741825, 1073741823, 1073741824]", sizeof(stream) - 1, stream);
+		helper_script_roundtrip("numbers", "[-2147483648, -2147483649, 2.147483647e+9, 2147483648]",
+				"[-2147483648, -2147483649, 2147483647, 2147483648]", sizeof(stream) - 1, stream);
 	}
 
 	void test_script_exceptions()
diff -r 6b3ac7e864ba source/sound/JSI_Sound.cpp
--- a/source/sound/JSI_Sound.cpp	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/sound/JSI_Sound.cpp	Thu Nov 04 14:52:01 2010 +0000
@@ -28,21 +28,14 @@
 {
 	m_Handle = snd_open(g_VFS, pathname);
 
-	// special-case to avoid throwing exceptions if quickstart has
-	// disabled sound: set a flag queried by Construct; the object will
-	// then immediately be freed.
-	if (m_Handle == ERR::AGAIN)
+	// if open failed, we still have to return a valid non-null object to
+	// the script, so just reset the handle to 0 so all subsequent method
+	// calls will do nothing
+	if (m_Handle < 0)
 	{
-		m_SoundDisabled = true;
+		m_Handle = 0;
 		return;
 	}
-	m_SoundDisabled = false;
-
-	// if open failed, raise an exception - it's the only way to
-	// report errors, since we're in the ctor and don't want to move
-	// the open call elsewhere (by requiring an explicit open() call).
-	if (m_Handle < 0)
-		throw std::exception(); // caught by JSI_Sound::Construct.
 
 	(void)snd_set_pos(m_Handle, 0,0,0, true);
 }
@@ -190,35 +183,17 @@
 	return "[object Sound: " + CStr(h_filename(m_Handle).string()) + "]";
 }
 
-JSBool JSI_Sound::Construct(JSContext* cx, JSObject* UNUSED(obj), uintN argc, jsval* argv, jsval* rval)
+JSBool JSI_Sound::Construct(JSContext* cx, uintN argc, jsval* vp)
 {
-	debug_assert(argc >= 1); // FIXME
+	JSU_REQUIRE_MIN_PARAMS(1);
+
 	CStrW filename;
-	if (! ToPrimitive<CStrW>(cx, argv[0], filename))
+	if (! ToPrimitive<CStrW>(cx, JS_ARGV(cx, vp)[0], filename))
 		return JS_FALSE;
 
-	try
-	{
-		JSI_Sound* newObject = new JSI_Sound(filename);
-
-		// somewhat of a hack to avoid throwing exceptions if
-		// sound was disabled due to quickstart. see JSI_Sound().
-		if (newObject->m_SoundDisabled)
-		{
-			delete newObject;
-			*rval = JSVAL_NULL;
-			return JS_TRUE;
-		}
-
-		newObject->m_EngineOwned = false;
-		*rval = OBJECT_TO_JSVAL(newObject->GetScript());
-	}
-	catch (std::exception)
-	{
-		// failed, but this can happen easily enough that we don't want to
-		// return JS_FALSE (since that stops the script).
-		*rval = JSVAL_NULL;
-	}
+	JSI_Sound* newObject = new JSI_Sound(filename);
+	newObject->m_EngineOwned = false;
+	JS_SET_RVAL(cx, vp, OBJECT_TO_JSVAL(newObject->GetScript()));
 
 	return JS_TRUE;
 }
diff -r 6b3ac7e864ba source/sound/JSI_Sound.h
--- a/source/sound/JSI_Sound.h	Wed Nov 03 17:52:07 2010 +0000
+++ b/source/sound/JSI_Sound.h	Thu Nov 04 14:52:01 2010 +0000
@@ -48,34 +48,31 @@
 
 	// Script-bound functions
 
-	CStr ToString( JSContext* cx, uintN argc, jsval* argv );
+	CStr ToString(JSContext* cx, uintN argc, jsval* argv);
 
 	// start playing the sound (one-shot).
 	// it will automatically be freed when done.
-	bool Play( JSContext* cx, uintN argc, jsval* argv );
+	bool Play(JSContext* cx, uintN argc, jsval* argv);
 
 	// request the sound be played until free() is called. returns immediately.
-	bool Loop( JSContext* cx, uintN argc, jsval* argv );
+	bool Loop(JSContext* cx, uintN argc, jsval* argv);
 
 	// stop sound if currently playing and free resources.
 	// doesn't need to be called unless played via loop() -
 	// sounds are freed automatically when done playing.
-	bool Free( JSContext* cx, uintN argc, jsval* argv );
+	bool Free(JSContext* cx, uintN argc, jsval* argv);
 
-	bool SetGain( JSContext* cx, uintN argc, jsval* argv );
+	bool SetGain(JSContext* cx, uintN argc, jsval* argv);
 
-	bool SetPitch( JSContext* cx, uintN argc, jsval* argv );
+	bool SetPitch(JSContext* cx, uintN argc, jsval* argv);
 
-	bool SetPosition( JSContext* cx, uintN argc, jsval* argv );
+	bool SetPosition(JSContext* cx, uintN argc, jsval* argv);
 
-	bool Fade ( JSContext* cx, uintN argc, jsval* argv );
+	bool Fade(JSContext* cx, uintN argc, jsval* argv);
 
-	static JSBool Construct( JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval );
+	static JSBool Construct(JSContext* cx, uintN argc, jsval* vp);
 
 	static void ScriptingInit();
-
-private:
-	bool m_SoundDisabled;	// see constructor and JSI_Sound::Construct
 };
 
 #endif	// #ifndef INCLUDED_JSI_SOUND
