📄 jsicontext.cpp
字号:
/***************************************************************************** ***************************************************************************** * * $Id: JsiContext.cpp,v 1.34.6.4 2001/10/03 16:20:52 dmeyer Exp $ * * JsiContext, class for managing JavaScript contexts * * The JsiContext class represents a JavaScript context, a script * execution state. All JavaScript variables are maintained in a * context, and all scripts are executed in reference to a context * (for accessing variables and maintaining script side-effects). Each * context may have one or more scopes that are used to layer the * state information so that it is possible for clients to control the * lifetime of state information within the context. * SBjsiInterface, definition of the real SBjsi resource object * ***************************************************************************** ****************************************************************************//****************License************************************************ * * Copyright 2000-2001. SpeechWorks International, Inc. * * Use of this software is subject to notices and obligations set forth * in the SpeechWorks Public License - Software Version 1.1 which is * included with this software. * * SpeechWorks is a registered trademark, and SpeechWorks Here, * DialogModules and the SpeechWorks logo are trademarks of SpeechWorks * International, Inc. in the United States and other countries. * ************************************************************************ */static const char *rcsid = 0 ? (char *) &rcsid :"$Id: JsiContext.cpp,v 1.34.6.4 2001/10/03 16:20:52 dmeyer Exp $";// -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8#include "SBjsiInternal.h"#include <string.h> // For strlen( )#include <jsapi.h> // SpiderMonkey API#include "SBjsiLog.h" // For logging#include "SBinetString.hpp" // For SBinetString#include "JsiRuntime.hpp" // For the JsiRuntime class#include "JsiContext.hpp" // Defines this class// SpiderMonkey class that describes our scope objects which we use// as contextsstatic JSClass SCOPE_CLASS = { "__SBjsiScope", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JsiContext::ScopeFinalize, JSCLASS_NO_OPTIONAL_MEMBERS};// SpiderMonkey class that describes our content objects which we use// to point at VXIContent objectsstatic JSClass CONTENT_CLASS = { "__SBjsiContent", JSCLASS_HAS_PRIVATE, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JsiContext::ContentFinalize, JSCLASS_NO_OPTIONAL_MEMBERS};// SpiderMonkey class that describes our objects which we create from// a VXIMap, just very simple objectsstatic JSClass MAP_CLASS = { "__SBjsiMap", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub, JSCLASS_NO_OPTIONAL_MEMBERS};// Names for JS objects we protect from garbage collection, only used// for SpiderMonkey debugging purposesstatic const char GLOBAL_SCOPE_NAME[] = "__SBjsiGlobalScope";static const wchar_t GLOBAL_SCOPE_NAME_W[] = L"__SBjsiGlobalScope";static const char SCRIPT_OBJECT_NAME[] = "__SBjsiScriptObject";static const char PROTECTED_JSVAL_NAME[] = "__SBjsiProtectedJsval";// Global variable we use for temporariesstatic const char GLOBAL_TEMP_VAR[] = "__SBjsiTempVar";static const wchar_t GLOBAL_TEMP_VAR_W[] = L"__SBjsiTempVar";// -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8// Macros and objects used to efficiently convert between VXIchar (native// OS wchar_t, usually 16 bits but under GNU gcc 32 bits) and jschar// (SpiderMonkey 16 bit).class JsiConvertJschar { public: JsiConvertJschar(const jschar *in) : len(0), str(NULL) { if (in) { while (in[len]) len++; } str = new VXIchar [len + 1]; str[len] = 0; for (size_t i = 0; i < len; i++) str[i] = in[i]; } ~JsiConvertJschar( ) { if (str) delete [] str; } const VXIchar *Get( ) const { return str; } size_t GetLength( ) const { return len; } private: size_t len; VXIchar *str;};class JsiConvertVXIchar { public: JsiConvertVXIchar(const VXIchar *in) : len(0), str(NULL) { if (in) len = wcslen (in); str = new jschar [len + 1]; str[len] = 0; for (size_t i = 0; i < len; i++) str[i] = (jschar) in[i]; } ~JsiConvertVXIchar( ) { if (str) delete [] str; } const jschar *Get( ) const { return str; } size_t GetLength( ) const { return len; } private: size_t len; jschar *str;};#ifdef VXICHAR_SIZE_16_BITS#define GET_VXICHAR_FROM_JSCHAR(out, in) \ const VXIchar *out = (const VXIchar *) in#define GET_JSCHAR_FROM_VXICHAR(out, outlen, in) \ const jschar *out = (const jschar *) in; \ size_t outlen = wcslen(in)#else /* not VXICHAR_SIZE_16_BITS */#define GET_VXICHAR_FROM_JSCHAR(out, in) \ JsiConvertJschar convert_##out(in); \ const VXIchar *out = convert_##out.Get( )#define GET_JSCHAR_FROM_VXICHAR(out, outlen, in) \ JsiConvertVXIchar convert_##out(in); \ const jschar *out = convert_##out.Get( ); \ size_t outlen = convert_##out.GetLength( )#endif /* VXICHAR_SIZE_16_BITS */// -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8// Wrapper class around jsval that automatically protects the held// jsval from garbage collectionclass JsiProtectedJsval { public: // Constructor and destructor JsiProtectedJsval (JSContext *c) : context(c), val(JSVAL_VOID) { } ~JsiProtectedJsval( ) { Clear( ); } // Clear the value VXIjsiResult Clear( ) { VXIjsiResult rc; rc = ((( JSVAL_IS_GCTHING(val) ) && ( ! JS_RemoveRoot (context, &val) )) ? VXIjsi_RESULT_FATAL_ERROR : VXIjsi_RESULT_SUCCESS); val = JSVAL_VOID; return rc; } // Set the value VXIjsiResult Set (jsval v) { VXIjsiResult rc = Clear( ); val = v; if (( JSVAL_IS_GCTHING(val) ) && ( ! JS_AddNamedRoot (context, &val, PROTECTED_JSVAL_NAME) )){ rc = VXIjsi_RESULT_OUT_OF_MEMORY; // blown away by GC already! } return rc; } // Accessor const jsval Get( ) const { return val; } private: // Disabled copy constructor and assignment operator JsiProtectedJsval (const JsiProtectedJsval &v); JsiProtectedJsval &operator=(const JsiProtectedJsval &v); private: JSContext *context; jsval val;};// -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8// Scope chain class, used to keep the scope chain independantly of// the actual user visible scope chain to avoid crashes from invalid// or malicious scripts (push a scope called "session", then overwrite// that variable with an integer named "session", then try to do more// work in that scope)class JsiScopeChainNode { public: // Constructor and destructor JsiScopeChainNode (JSContext *context, JsiScopeChainNode *p, const VXIchar *n) : name(n), parent(p), child(NULL), jsVal(context) { } ~JsiScopeChainNode( ) { } // Creation method VXIjsiResult Create (JSObject *scopeObj) { return jsVal.Set (OBJECT_TO_JSVAL(scopeObj)); } // Accessors const SBinetString & GetName( ) const { return name; } jsval GetJsval( ) { return jsVal.Get( ); } JSObject * GetJsobj( ) { return JSVAL_TO_OBJECT(jsVal.Get( )); } JsiScopeChainNode * GetParent( ) { return parent; } JsiScopeChainNode * GetChild( ) { return child; } // Set the child scope void SetChild (JsiScopeChainNode *c) { child = c; } // Release this scope and all under it VXIjsiResult Release( ); private: SBinetString name; // Name of this scope JsiScopeChainNode *parent; // Parent scope JsiScopeChainNode *child; // Child scope, may be NULL JsiProtectedJsval jsVal; // JS object for the scope};VXIjsiResult JsiScopeChainNode::Release( ){ JsiScopeChainNode *node = this, *next = NULL; while (node) { // Release the lock on the underlying object node->jsVal.Clear( ); // Clear pointers for safety and advance to child scopes next = node->child; node->parent = NULL; node->child = NULL; node = next; // NOTE: the deletion of this node and the child nodes is handled // by the ScopeFinalize( ) method that is called when the JS // object is garbage collected } return VXIjsi_RESULT_SUCCESS;}// -----1=0-------2=0-------3=0-------4=0-------5=0-------6=0-------7=0-------8// Constructor, only does initialization that cannot failJsiContext::JsiContext( ) : SBinetLogger (MODULE_SBJSI, NULL, 0), version(JSVERSION_DEFAULT), runtime(NULL), context(NULL), contextRefs(0), scopeChain(NULL), currentScope(NULL), logEnabled(true), maxBranches(0L), numBranches(0L), exception(NULL){}// DestructorJsiContext::~JsiContext( ){ Diag (SBJSI_LOG_CONTEXT, L"JsiContext::~JsiContext", L"start 0x%p, JS context 0x%p", this, context); if ( exception ) VXIValueDestroy (&exception); if ( context ) { // Lock the context for access#ifdef JS_THREADSAFE JS_ResumeRequest (context, contextRefs);#else if ( ! AccessBegin( ) ) return;#endif // Destroy the scope chain, which automatically unroots the global // scope to allow garbage collection of everything if ( scopeChain ) scopeChain->Release( ); // Release the lock, must be done before destroying the context#ifdef JS_THREADSAFE JS_EndRequest (context);#else AccessEnd( );#endif // Destroy the context, is set to NULL runtime->DestroyContext (&context); } Diag (SBJSI_LOG_CONTEXT, L"JsiContext::~JsiContext", L"end 0x%p", this);}// Creation methodVXIjsiResult JsiContext::Create (JsiRuntime *rt, long contextSize, long mb, VXIlogInterface *l, VXIunsigned diagTagBase){ if (( rt == NULL ) || ( contextSize < 1 ) || ( mb < 1 ) || ( l == NULL )) return VXIjsi_RESULT_INVALID_ARGUMENT; // Copy simple variables runtime = rt; maxBranches = mb; // Base logging class initialization SetLog (l, diagTagBase); Diag (SBJSI_LOG_CONTEXT, L"JsiContext::Create", L"start 0x%p", this); // Create the context VXIjsiResult rc = runtime->NewContext (contextSize, &context); if ( rc != VXIjsi_RESULT_SUCCESS ) return rc; // Lock the context for access#ifdef JS_THREADSAFE JS_BeginRequest (context);#else if ( AccessBegin( ) != true ) rc = VXIjsi_RESULT_SYSTEM_ERROR;#endif // Attach this as private data to the context for use in callbacks if ( rc == VXIjsi_RESULT_SUCCESS ) JS_SetContextPrivate (context, this); // Set the callback to enforce maxBranches if ( rc == VXIjsi_RESULT_SUCCESS ) JS_SetBranchCallback (context, JsiContext::BranchCallback); // Set the callback for reporting errors if ( rc == VXIjsi_RESULT_SUCCESS ) JS_SetErrorReporter (context, JsiContext::ErrorReporter);#if 0 // Enable strictness, which provides additional warnings/errors. // NOTE: Disabled for now, may want this configurable in the future. if ( rc == VXIjsi_RESULT_SUCCESS ) JS_SetOptions (context, JSOPTION_STRICT);#endif // Create and intialize the global scope we require in the context, // the scope chain node object locks it to protect it from the // garbage collector if ( rc == VXIjsi_RESULT_SUCCESS ) { JSObject *globalScope = JS_NewObject (context, &SCOPE_CLASS, NULL, NULL); if ( ! globalScope ) rc = VXIjsi_RESULT_OUT_OF_MEMORY; else { Diag (SBJSI_LOG_SCOPE, L"JsiContext::Create", L"global scope 0x%p, context 0x%p", globalScope, context); scopeChain = new JsiScopeChainNode (context, NULL, GLOBAL_SCOPE_NAME_W); if ( scopeChain ) { rc = scopeChain->Create (globalScope); if ( rc == VXIjsi_RESULT_SUCCESS ) { if ( JS_SetPrivate (context, globalScope, scopeChain) ) currentScope = scopeChain; else rc = VXIjsi_RESULT_FATAL_ERROR; } } else { rc = VXIjsi_RESULT_OUT_OF_MEMORY; } } } // Initialize the standard JavaScript classes, like Array, Math, String, etc. if (( rc == VXIjsi_RESULT_SUCCESS ) && ( ! JS_InitStandardClasses (context, currentScope->GetJsobj( )) )) rc = VXIjsi_RESULT_OUT_OF_MEMORY; // Set version only after there is a valid global scope object if (( rc == VXIjsi_RESULT_SUCCESS ) && ( version != JSVERSION_DEFAULT )) JS_SetVersion (context, version); // On failure, destroy the context here to avoid use of it if ( rc != VXIjsi_RESULT_SUCCESS ) { if ( context ) {#ifdef JS_THREADSAFE JS_EndRequest (context);#endif runtime->DestroyContext (&context); } }#ifdef JS_THREADSAFE else { contextRefs = JS_SuspendRequest (context); }#else if ( AccessEnd( ) != true ) rc = VXIjsi_RESULT_SYSTEM_ERROR;#endif Diag (SBJSI_LOG_CONTEXT, L"JsiContext::Create", L"end 0x%p, JS context 0x%p", this, context); return rc;}// Create a script variable relative to the current scope
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -