You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ft...@apache.org on 2014/04/30 11:59:00 UTC

[11/15] FLEX-34291: Merge the donated FDB with the current one.

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/379cb609/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSession.java
----------------------------------------------------------------------
diff --git a/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSession.java b/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSession.java
index e2b0b62..5d25b83 100644
--- a/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSession.java
+++ b/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSession.java
@@ -1,20 +1,18 @@
 /*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package flash.tools.debugger.concrete;
@@ -42,7 +40,11 @@ import java.util.regex.Pattern;
 import flash.tools.debugger.AIRLaunchInfo;
 import flash.tools.debugger.Frame;
 import flash.tools.debugger.IDebuggerCallbacks;
+import flash.tools.debugger.ILauncher;
 import flash.tools.debugger.InProgressException;
+import flash.tools.debugger.Isolate;
+import flash.tools.debugger.IsolateController;
+import flash.tools.debugger.IsolateSession;
 import flash.tools.debugger.Location;
 import flash.tools.debugger.NoResponseException;
 import flash.tools.debugger.NotConnectedException;
@@ -71,7 +73,7 @@ import flash.tools.debugger.expression.PlayerFaultException;
 import flash.util.Trace;
 
 
-public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
+public class PlayerSession implements Session, DProtocolNotifierIF, Runnable, IsolateController
 {
 	public static final int MAX_STACK_DEPTH = 256;
 	public static final long MAX_TERMINATE_WAIT_MILLIS = 10000;
@@ -88,10 +90,16 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	private volatile boolean m_isHalted; // WARNING -- accessed from multiple threads
 	private volatile boolean m_incoming; // WARNING -- accessed from multiple threads
 	private volatile boolean m_lastResponse;  // whether there was a reponse from the last message to the Player
+	private volatile HashMap<Integer, PlayerSessionIsolateStatus> m_isolateStatus = new HashMap<Integer, PlayerSessionIsolateStatus>();
+	
 	private int				m_watchTransactionTag;
 	private Boolean			m_playerCanCallFunctions;
 	private Boolean			m_playerSupportsWatchpoints;
 	private Boolean			m_playerCanBreakOnAllExceptions;
+	private Boolean			m_playerSupportsConcurrency;
+	private Boolean			m_playerSupportsWideLine;
+	
+	private ILauncher launcher;
 
 	/**
 	 * The URL that was launched, or <code>null</code> if not known.  Note:
@@ -109,11 +117,16 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	static volatile boolean	m_debugMsgFileOn;	// debug ONLY for file dump; turned on with "set $debug_message_file = 1"
 	volatile int			m_debugMsgFileSize;	// debug ONLY for file dump; controlled with "set $debug_message_file_size = NNN"
 
+	//FIXME: Make this concurrency aware
 	/**
 	 * A simple cache of previous "is" and "instanceof" queries, in order to
 	 * avoid having to send redundant messages to the player.
 	 */
 	private Map<String, Boolean> m_evalIsAndInstanceofCache = new HashMap<String, Boolean>();
+	
+	private volatile int m_lastPreIsolate = Isolate.DEFAULT_ID;
+	
+	private final Map<Integer, IsolateSession> m_isolateSessions;
 
 	private static final String DEBUG_MESSAGES = "$debug_messages"; //$NON-NLS-1$
 	private static final String DEBUG_MESSAGE_SIZE = "$debug_message_size"; //$NON-NLS-1$
@@ -123,7 +136,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	private static final String CONSOLE_ERRORS = "$console_errors"; //$NON-NLS-1$
 
 	private static final String FLASH_PREFIX = "$flash_"; //$NON-NLS-1$
-
+	
 	PlayerSession(Socket s, DProtocol proto, DManager manager, IDebuggerCallbacks debuggerCallbacks)
 	{
 		m_isConnected = false;
@@ -140,6 +153,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		m_watchTransactionTag = 1;  // number that is sent for each watch transaction that occurs
 		m_playerCanCallFunctions = null;
 		m_debuggerCallbacks = debuggerCallbacks;
+		m_isolateSessions = Collections.synchronizedMap(new HashMap<Integer, IsolateSession>());
 	}
 	
 	private static PlayerSession createFromSocketHelper(Socket s, IDebuggerCallbacks debuggerCallbacks, DProtocol proto) throws IOException
@@ -156,7 +170,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 * @param s
 	 * @param debuggerCallbacks
 	 * @return
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static PlayerSession createFromSocket(Socket s, IDebuggerCallbacks debuggerCallbacks) throws IOException
 	{
@@ -172,7 +186,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 * @param debuggerCallbacks
 	 * @param sessionManager
 	 * @return
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	public static PlayerSession createFromSocketWithOptions(Socket s, IDebuggerCallbacks debuggerCallbacks, SessionManager sessionManager) throws IOException
 	{
@@ -298,6 +312,24 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 		return m_isHalted;
 	}
+	
+	/*
+	 * @see flash.tools.debugger.Session#isIsolateSuspended()
+	 */
+	public boolean isWorkerSuspended(int isolateId) throws NotConnectedException
+	{
+		if (isolateId == Isolate.DEFAULT_ID)
+			return isSuspended();
+		
+		if (!isConnected())
+			throw new NotConnectedException();
+		
+		if (m_isolateStatus.containsKey(isolateId)) {
+			return m_isolateStatus.get(isolateId).m_isHalted;
+		}
+		
+		return false;
+	}
 
 	/**
 	 * Start up the session listening for incoming messages on the socket
@@ -328,10 +360,17 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		sendSwfloadNotify();
 		sendGetterTimeout();
 		sendSetterTimeout();
-		boolean responded = sendSquelch(true);
+		boolean responded = sendSquelch(true, Isolate.DEFAULT_ID);
 
 		// now note in our preferences whether get is working or not.
 		setPreference(SessionManager.PLAYER_SUPPORTS_GET, playerSupportsGet() ? 1 : 0);
+		if (supportsConcurrency()) {
+			sendConcurrentDebugger();
+		}
+		
+		if (supportsWideLineNumbers()) {
+			sendWideLineDebugger();
+		}
 
 		// Spawn a background thread which fetches the SWF and SWD
 		// from the Player and uses them to build function name tables
@@ -444,7 +483,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 *            AppleScript via "item 1 or argv", "item 2 of argv", etc.
 	 * @return any text which was sent to stdout by /usr/bin/osascript, with the
 	 *         trailing \n already removed
-	 * @throws IOException
+	 * @throws java.io.IOException
 	 */
 	private String executeAppleScript(String appleScriptFilename, String[] argv) throws IOException
 	{
@@ -591,7 +630,15 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 			{
 				try
 				{
-					m_debuggerCallbacks.terminateDebugTarget(m_process);
+					//if a launcher is set for handling the launcher operations then use it.
+					if(null != launcher)
+					{
+						m_debuggerCallbacks.terminateDebugTarget(m_process,launcher);
+					}
+					else
+					{
+						m_debuggerCallbacks.terminateDebugTarget(m_process);
+					}
 				}
 				catch (IOException e)
 				{
@@ -655,12 +702,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public void resume() throws NotSuspendedException, NotConnectedException, NoResponseException
 	{
-		// send a continue message then return
-		if (!isSuspended())
-			throw new NotSuspendedException();
-
-		if (!simpleRequestResponseMessage(DMessage.OutContinue, DMessage.InContinue))
-			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+		resumeWorker(Isolate.DEFAULT_ID);
 	}
 
 	/*
@@ -668,21 +710,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public void suspend() throws SuspendedException, NotConnectedException, NoResponseException
 	{
-		// send a halt message
-		int wait = getPreference(SessionManager.PREF_SUSPEND_WAIT);
- 		int every = 50; // wait this long for a response.  The lower the number the more aggressive we are!
-
-		if (isSuspended())
-			throw new SuspendedException();
-
-		while (!isSuspended() && wait > 0)
-		{
-			simpleRequestResponseMessage(DMessage.OutStopDebug, DMessage.InBreakAtExt, every);
-			wait -= every;
-		}
-
-		if (!isSuspended())
-			throw new NoResponseException(wait);
+		suspendWorker(Isolate.DEFAULT_ID);
 	}
 
 	/**
@@ -690,18 +718,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public DSuspendInfo getSuspendInfo()
 	{
-		DSuspendInfo info = m_manager.getSuspendInfo();
-		if (info == null)
-		{
-			// request break information
-			if (simpleRequestResponseMessage(DMessage.OutGetBreakReason, DMessage.InBreakReason))
-				info = m_manager.getSuspendInfo();
-
-			// if we still can't get any info from the manager...
-			if (info == null)
-				info = new DSuspendInfo();  // empty unknown break information
-		}
-		return info;
+		return getSuspendInfoIsolate(Isolate.DEFAULT_ID);
 	}
 
 	/**
@@ -745,25 +762,19 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public SwfInfo[] getSwfs() throws NoResponseException
 	{
-		if (m_manager.getSwfInfoCount() == 0)
-		{
-			// need to help out on the first one since the player
-			// doesn't send it
-			requestSwfInfo(0);
-		}
-		SwfInfo[] swfs = m_manager.getSwfInfos();
-		return swfs;
+		return getSwfsWorker(Isolate.DEFAULT_ID);
 	}
 
 	/**
 	 * Request information on a particular swf, used by DSwfInfo
 	 * to fill itself correctly
 	 */
-	public void requestSwfInfo(int at) throws NoResponseException
+	public void requestSwfInfo(int at, int isolateId) throws NoResponseException
 	{
 		// nope don't have it...might as well go out and ask for all of them.
 		DMessage dm = DMessageCache.alloc(4);
 		dm.setType( DMessage.OutSwfInfo );
+		dm.setTargetIsolate(isolateId);
 		dm.putWord(at);
 		dm.putWord(0);  // rserved
 
@@ -803,15 +814,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public void stepInto() throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
-		if (isSuspended())
-		{
-			// send a step-into message and then wait for the Flash player to tell us that is has
-			// resumed execution
-			if (!simpleRequestResponseMessage(DMessage.OutStepInto, DMessage.InContinue))
-				throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
-		}
-		else
-			throw new NotSuspendedException();
+		stepIntoWorker(Isolate.DEFAULT_ID);
 	}
 
 	/*
@@ -819,15 +822,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public void stepOut() throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
-		if (isSuspended())
-		{
-			// send a step-out message and then wait for the Flash player to tell us that is has
-			// resumed execution
-			if (!simpleRequestResponseMessage(DMessage.OutStepOut, DMessage.InContinue))
-				throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
-		}
-		else
-			throw new NotSuspendedException();
+		stepOutWorker(Isolate.DEFAULT_ID);
 	}
 
 	/*
@@ -835,15 +830,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public void stepOver() throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
-		if (isSuspended())
-		{
-			// send a step-over message and then wait for the Flash player to tell us that is has
-			// resumed execution
-			if (!simpleRequestResponseMessage(DMessage.OutStepOver, DMessage.InContinue))
-				throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
-		}
-		else
-			throw new NotSuspendedException();
+		stepOverWorker(Isolate.DEFAULT_ID);
 	}
 
 	/*
@@ -869,13 +856,14 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
      * @param lineNbr
      * @return
      */
-    public void requestFunctionNames(int moduleId, int lineNbr) throws VersionException, NoResponseException
+    public void requestFunctionNames(int moduleId, int lineNbr, int isolateId) throws VersionException, NoResponseException
     {
         // only player 9 supports this message
         if (m_manager.getVersion() >= 9)
         {
             DMessage dm = DMessageCache.alloc(8);
             dm.setType(DMessage.OutGetFncNames);
+            dm.setTargetIsolate(isolateId);
             dm.putDWord(moduleId);
             dm.putDWord(lineNbr);
 
@@ -891,9 +879,9 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	/**
 	 * From a given file identifier return a source file object
 	 */
-	public SourceFile getFile(int fileId)
+	public SourceFile getFile(int fileId, int isolateId)
 	{
-		return m_manager.getSource(fileId);
+		return m_manager.getSource(fileId, isolateId);
 	}
 
 	/**
@@ -901,7 +889,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public Location[] getBreakpointList()
 	{
-		return m_manager.getBreakpoints();
+		return m_manager.getBreakpoints(Isolate.DEFAULT_ID);
 	}
 
 	/*
@@ -909,25 +897,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public Location setBreakpoint(int fileId, int lineNum) throws NoResponseException, NotConnectedException
 	{
-		/* send the message to the player and await a response */
-		Location l = null;
-		int bp = DLocation.encodeId(fileId, lineNum);
-
-		DMessage dm = DMessageCache.alloc(8);
-		dm.setType(DMessage.OutSetBreakpoints);
-		dm.putDWord(1);
-		dm.putDWord(bp);
-
-		boolean gotResponse = simpleRequestResponseMessage(dm, DMessage.InSetBreakpoint);
-		if(gotResponse)
-		{
-			/* even though we think we got an answer check that the breakpoint was added */
-			l = m_manager.getBreakpoint(bp);
-		}
-		else
-			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
-
-		return l;
+		return setBreakpointWorker(fileId, lineNum, Isolate.DEFAULT_ID);
 	}
 
 	/*
@@ -940,18 +910,30 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		int fileId = source.getId();
 		int lineNum = local.getLine();
 		int bp = DLocation.encodeId(fileId, lineNum);
-		Location l = m_manager.getBreakpoint(bp);
+		int isolateId = local.getIsolateId();
+		Location l = null;
+		l = m_manager.getBreakpoint(bp, isolateId);
+		
 		if (l != null)
 		{
 			/* send the message */
-			DMessage dm = DMessageCache.alloc(8);
+			int wideLineSize = 0;
+			if (supportsWideLineNumbers())
+				wideLineSize = 4;
+			DMessage dm = DMessageCache.alloc(8 + wideLineSize);
 			dm.setType(DMessage.OutRemoveBreakpoints);
+			dm.setTargetIsolate(isolateId);
 			dm.putDWord(1);
-			dm.putDWord(bp);
+			if (!supportsWideLineNumbers())
+				dm.putDWord(bp);
+			else {
+				dm.putDWord(fileId);
+				dm.putDWord(lineNum);
+			}
 			sendMessage(dm);
 
 			/* no callback from the player so we remove it ourselves */
-			m_manager.removeBreakpoint(bp);
+			m_manager.removeBreakpoint(bp, isolateId);
 		}
 		return l;
 	}
@@ -961,10 +943,18 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public Watch[] getWatchList() throws NoResponseException, NotConnectedException
 	{
-		return m_manager.getWatchpoints();
+		return getWatchListWorker(Isolate.DEFAULT_ID);
+	}
+	
+	/*
+	 * @see flash.tools.debugger.Session#getWatchList()
+	 */
+	public Watch[] getWatchListWorker(int isolateId) throws NoResponseException, NotConnectedException
+	{
+			return m_manager.getWatchpoints(isolateId);
 	}
 
-	private Watch setWatch(long varId, String memberName, int kind) throws NoResponseException, NotConnectedException, NotSupportedException
+	private Watch setWatch(long varId, String memberName, int kind, int isolateId) throws NoResponseException, NotConnectedException, NotSupportedException
 	{
 		// we really have two cases here, one where we add a completely new
 		// watchpoint and the other where we modify an existing one.
@@ -973,32 +963,32 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		Watch w = null;
 		int tag = m_watchTransactionTag++;
 
-		if (addWatch(varId, memberName, kind, tag))
+		if (addWatch(varId, memberName, kind, tag, isolateId))
 		{
 			// good that we got a response now let's check that
 			// it actually worked.
-			int count = m_manager.getWatchpointCount();
+			int count = m_manager.getWatchpointCount(isolateId);
 			if (count > 0)
 			{
-				DWatch lastWatch = m_manager.getWatchpoint(count-1);
+				DWatch lastWatch = m_manager.getWatchpoint(count-1, isolateId);
 				if (lastWatch.getTag() == tag)
 					w = lastWatch;
 			}
 		}
 		return w;
 	}
-
+	
 	/*
 	 * @see flash.tools.debugger.Session#setWatch(flash.tools.debugger.Variable, java.lang.String, int)
 	 */
 	public Watch setWatch(Value v, String memberName, int kind) throws NoResponseException, NotConnectedException, NotSupportedException
 	{
-		return setWatch(v.getId(), memberName, kind);
+		return setWatch(v.getId(), memberName, kind, v.getIsolateId());
 	}
 
 	public Watch setWatch(Watch watch) throws NoResponseException, NotConnectedException, NotSupportedException
 	{
-		return setWatch(watch.getValueId(), watch.getMemberName(), watch.getKind());
+		return setWatch(watch.getValueId(), watch.getMemberName(), watch.getKind(), watch.getIsolateId());
 	}
 
 	/*
@@ -1006,17 +996,17 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public Watch clearWatch(Watch watch) throws NoResponseException, NotConnectedException
 	{
-		Watch[] list = getWatchList();
+		Watch[] list = getWatchListWorker(watch.getIsolateId());
 		Watch w = null;
-		if ( removeWatch(watch.getValueId(), watch.getMemberName()) )
+		if ( removeWatch(watch.getValueId(), watch.getMemberName(), watch.getIsolateId()) )
 		{
 			// now let's first check the size of the list, it
 			// should now be one less
-			if (m_manager.getWatchpointCount() < list.length)
+			if (m_manager.getWatchpointCount(watch.getIsolateId()) < list.length)
 			{
 				// ok we made a change. So let's compare list and see which
 				// one went away
-				Watch[] newList = getWatchList();
+				Watch[] newList = getWatchListWorker(watch.getIsolateId());
 				for(int i=0; i<newList.length; i++)
 				{
 					// where they differ is the missing one
@@ -1040,29 +1030,34 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public Variable[] getVariableList() throws NotSuspendedException, NoResponseException, NotConnectedException, VersionException
 	{
+		return getVariableListWorker(Isolate.DEFAULT_ID);
+	}
+	
+	public Variable[] getVariableListWorker(int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException, VersionException
+	{
 		// make sure the player has stopped and send our message awaiting a response
-		if (!isSuspended())
+		if (!isWorkerSuspended(isolateId))
 			throw new NotSuspendedException();
 
-		requestFrame(0);  // our 0th frame gets our local context
+		requestFrame(0, isolateId);  // our 0th frame gets our local context
 
 		// now let's request all of the special variables too
-		getValue(Value.GLOBAL_ID);
-		getValue(Value.THIS_ID);
-		getValue(Value.ROOT_ID);
+		getValueWorker(Value.GLOBAL_ID, isolateId);
+		getValueWorker(Value.THIS_ID, isolateId);
+		getValueWorker(Value.ROOT_ID, isolateId);
 
 		// request as many levels as we can get
 		int i = 0;
 		Value v = null;
 		do
 		{
-			v = getValue(Value.LEVEL_ID-i);
+			v = getValueWorker(Value.LEVEL_ID-i, isolateId);
 		}
 		while( i++ < 128 && v != null);
 
 		// now that we've primed the DManager we can request the base variable whose
 		// children are the variables that are available
-		v = m_manager.getValue(Value.BASE_ID);
+		v = m_manager.getValue(Value.BASE_ID, isolateId);
 		if (v == null)
 			throw new VersionException();
 		return v.getMembers(this);
@@ -1073,33 +1068,34 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public Frame[] getFrames() throws NotConnectedException
 	{
-		return m_manager.getFrames();
+		return m_manager.getFrames(Isolate.DEFAULT_ID);
 	}
 
 	/**
 	 * Asks the player to return information regarding our current context which includes
 	 * this pointer, arguments for current frame, locals, etc.
 	 */
-	public void requestFrame(int depth) throws NotSuspendedException, NoResponseException, NotConnectedException
+	public void requestFrame(int depth, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
 		if (playerSupportsGet())
 		{
-			if (!isSuspended())
+			if (!isWorkerSuspended(isolateId))
 				throw new NotSuspendedException();
 
 			int timeout = getPreference(SessionManager.PREF_CONTEXT_RESPONSE_TIMEOUT);
 
 			DMessage dm = DMessageCache.alloc(4);
 			dm.setType(DMessage.OutGetFrame);
+			dm.setTargetIsolate(isolateId);
 			dm.putDWord(depth);  // depth of zero
 			if (!simpleRequestResponseMessage(dm,  DMessage.InFrame, timeout)) {
 				throw new NoResponseException(timeout);
 			}
 
-			pullUpActivationObjectVariables(depth);
+			pullUpActivationObjectVariables(depth, isolateId);
 		}
 	}
-
+	
 	/**
 	 * The compiler sometimes creates special local variables called
 	 * "activation objects."  When it decides to do this (e.g. if the
@@ -1115,10 +1111,12 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 *
 	 * @param depth the depth of the stackframe we are fixing; 0 is topmost
 	 */
-	private void pullUpActivationObjectVariables(int depth) throws NotSuspendedException, NoResponseException, NotConnectedException
+	private void pullUpActivationObjectVariables(int depth, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
-		DValue frame = m_manager.getValue(Value.BASE_ID-depth);
-		DStackContext context = m_manager.getFrame(depth);		
+		DValue frame = m_manager.getValue(Value.BASE_ID-depth, isolateId);
+		if (frame == null)
+			return;
+		DStackContext context = m_manager.getFrame(depth, isolateId);		
 		DVariable[] frameVars = (DVariable[]) frame.getMembers(this);
 		Map<String, DVariable> varmap = new LinkedHashMap<String, DVariable>(frameVars.length); // preserves order
 		List<DVariable> activationObjects = new ArrayList<DVariable>();
@@ -1198,28 +1196,33 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public Value getValue(long valueId) throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
+		return getValueWorker(valueId, Isolate.DEFAULT_ID);
+	}
+	
+	public Value getValueWorker(long valueId, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException
+	{
 		DValue val = null;
 
-		if (!isSuspended())
+		if (!isWorkerSuspended(isolateId))
 			throw new NotSuspendedException();
 
 		// get it from cache if we can
-		val = m_manager.getValue(valueId);
+		val = m_manager.getValue(valueId, isolateId);
 
 		if (val == null)
 		{
 			// if a special variable, then we need to trigger a local frame call, otherwise just use id to get it
 			if (valueId < Value.UNKNOWN_ID)
 			{
-				requestFrame(0); // force our current frame to get populated, BASE_ID will be available
+				requestFrame(0, isolateId); // force our current frame to get populated, BASE_ID will be available
 			}
 			else if (valueId > Value.UNKNOWN_ID)
 			{
-				requestVariable(valueId, null);
+				requestVariable(valueId, null, isolateId);
 			}
 
 			// after all this we should have our variable cache'd so try again if it wasn't there the first time
-			val = m_manager.getValue(valueId);
+			val = m_manager.getValue(valueId, isolateId);
 		}
 
 		return val;
@@ -1228,9 +1231,9 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	/**
 	 * Returns the current value object for the given id; never requests it from the player.
 	 */
-	public Value getRawValue(long valueId)
+	public Value getRawValue(long valueId, int isolateId)
 	{
-		return m_manager.getValue(valueId);
+		return m_manager.getValue(valueId, isolateId);
 	}
 
 	/**
@@ -1239,26 +1242,26 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 * player (because it can't, of course).  Returns <code>null</code> if we don't have
 	 * a value for that id.
 	 */
-	public Value getPreviousValue(long valueId)
+	public Value getPreviousValue(long valueId, int isolateId)
 	{
-		return m_manager.getPreviousValue(valueId);
+		return m_manager.getPreviousValue(valueId, isolateId);
 	}
 
 	/**
 	 * Launches a request to obtain all the members of the specified variable, and
 	 * store them in the variable which would be returned by
-	 * {@link DManager#getVariable(long)}.
+	 * {@link flash.tools.debugger.concrete.DManager#getVariable(long)}.
 	 *
 	 * @param valueId id of variable whose members we want; underlying Variable must
 	 * already be known by the PlayerSessionManager.
 	 *
-	 * @throws NoResponseException
-	 * @throws NotConnectedException
-	 * @throws NotSuspendedException
+	 * @throws flash.tools.debugger.NoResponseException
+	 * @throws flash.tools.debugger.NotConnectedException
+	 * @throws flash.tools.debugger.NotSuspendedException
 	 */
-	void obtainMembers(long valueId) throws NoResponseException, NotConnectedException, NotSuspendedException
+	void obtainMembers(long valueId, int isolateId) throws NoResponseException, NotConnectedException, NotSuspendedException
 	{
-		if (!isSuspended())
+		if (!isWorkerSuspended(isolateId))
 			throw new NotSuspendedException();
 
 		// Get it from cache.  Normally, this should never fail; however, in
@@ -1266,17 +1269,22 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		// that a thread has called this even after a different thread has
 		// single-stepped, so that the original variable is no longer valid.
 		// So, we'll check for a null return value.
-		DValue v = m_manager.getValue(valueId);
+		DValue v = m_manager.getValue(valueId, isolateId);
 
 		if (v != null && !v.membersObtained())
 		{
-			requestVariable(valueId, null, false, true);
+			requestVariable(valueId, null, false, true, isolateId);
 		}
 	}
 
 	public Value getGlobal(String name) throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
-		Value v = getValue(0, name);
+		return getGlobalWorker(name, Isolate.DEFAULT_ID);
+	}
+	
+	public Value getGlobalWorker(String name, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException
+	{
+		Value v = getValue(0, name, isolateId);
 
 		if (v==null || v.getType() == VariableType.UNDEFINED)
 			return null;
@@ -1297,27 +1305,27 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 * paragraph was written for AS2; __proto__ doesn't exist
 	 * in AS3.  TODO: revise this paragraph]
 	 */
-	public Value getValue(long varId, String name) throws NotSuspendedException, NoResponseException, NotConnectedException
+	public Value getValue(long varId, String name, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
 		Value v = null;
-		if (isSuspended())
+		if (isWorkerSuspended(isolateId))
 		{
 			int fireGetter = getPreference(SessionManager.PREF_INVOKE_GETTERS);
 
 			// disable children attaching to parent variables and clear our
 			// most recently seen variable
-			m_manager.clearLastVariable();
-			m_manager.enableChildAttach(false);
+			m_manager.clearLastVariable(isolateId);
+			m_manager.enableChildAttach(false, isolateId);
 
 			try
 			{
-				requestVariable(varId, name, (fireGetter != 0), false);
+				requestVariable(varId, name, (fireGetter != 0), false, isolateId);
 
-				DVariable lastVariable = m_manager.lastVariable();
+				DVariable lastVariable = m_manager.lastVariable(isolateId);
 				if (lastVariable != null)
 					v = lastVariable.getValue();
 				else
-					v = DValue.forPrimitive(Value.UNDEFINED);
+					v = DValue.forPrimitive(Value.UNDEFINED, isolateId);
 			}
 			catch (NoResponseException e)
 			{
@@ -1333,11 +1341,11 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 					// because in every other case, this function does not add members to
 					// existing objects.  Need to revisit this.
 					v = new DValue(VariableType.STRING, "String", "String", ValueAttribute.IS_EXCEPTION, //$NON-NLS-1$ //$NON-NLS-2$
-							e.getLocalizedMessage());
+							e.getLocalizedMessage(), isolateId);
 					if (varId != 0) {
-						DVariable var = new DVariable(name, (DValue)v);
-						m_manager.enableChildAttach(true);
-						m_manager.addVariableMember(varId, var);
+						DVariable var = new DVariable(name, (DValue)v, isolateId);
+						m_manager.enableChildAttach(true, isolateId);
+						m_manager.addVariableMember(varId, var, isolateId);
 					}
 				}
 				else
@@ -1348,7 +1356,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 			finally
 			{
 				// reset our attach flag, so that children attach to parent variables.
-				m_manager.enableChildAttach(true);
+				m_manager.enableChildAttach(true, isolateId);
 			}
 		}
 		else
@@ -1357,9 +1365,9 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		return v;
 	}
 
-	private void requestVariable(long id, String name) throws NoResponseException, NotConnectedException, NotSuspendedException
+	private void requestVariable(long id, String name, int isolateId) throws NoResponseException, NotConnectedException, NotSuspendedException
 	{
-		requestVariable(id, name, false, false);
+		requestVariable(id, name, false, false, isolateId);
 	}
 
 	/**
@@ -1369,22 +1377,24 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 * @param args the args to the function
 	 * @return the return value of the function
 	 */
-	private Value callFunction(Value thisValue, boolean isConstructor, String funcname, Value[] args) throws PlayerDebugException
+	private Value callFunction(Value thisValue, boolean isConstructor, String funcname, Value[] args, int isolateId) throws PlayerDebugException
 	{
-		if (!isSuspended())
+		if (!isWorkerSuspended(isolateId))
 			throw new NotSuspendedException();
 
-		if (!playerCanCallFunctions())
+		if (!playerCanCallFunctions(isolateId))
 			throw new NotSupportedException(PlayerSessionManager.getLocalizationManager().getLocalizedTextString("functionCallsNotSupported")); //$NON-NLS-1$
 
 		// name = getRawMemberName(id, name);
 
-		m_manager.clearLastFunctionCall();
+		m_manager.clearLastFunctionCall(isolateId);
 
 		DMessage dm = buildCallFunctionMessage(isConstructor, thisValue, funcname, args);
 
+		dm.setTargetIsolate(isolateId);
+		
 		// make sure any exception during the setter gets held onto
-		m_manager.beginPlayerCodeExecution();
+		m_manager.beginPlayerCodeExecution(isolateId);
 
 		// TODO wrong timeout
 		int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT);
@@ -1393,16 +1403,16 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		boolean result = simpleRequestResponseMessage(dm, DMessage.InCallFunction, timeout);
 
 		// tell manager we're done; ignore returned FaultEvent
-		m_manager.endPlayerCodeExecution();
+		m_manager.endPlayerCodeExecution(isolateId);
 
 		if (!result)
 			throw new NoResponseException(timeout);
 
-		DVariable lastFunctionCall = m_manager.lastFunctionCall();
+		DVariable lastFunctionCall = m_manager.lastFunctionCall(isolateId);
 		if (lastFunctionCall != null)
 			return lastFunctionCall.getValue();
 		else
-			return DValue.forPrimitive(Value.UNDEFINED);
+			return DValue.forPrimitive(Value.UNDEFINED, isolateId);
 	}
 
 	/*
@@ -1410,12 +1420,17 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 */
 	public Value callFunction(Value thisValue, String funcname, Value[] args) throws PlayerDebugException
 	{
-		Value retval = callPseudoFunction(thisValue, funcname, args);
+		return callFunctionWorker(thisValue, funcname, args, Isolate.DEFAULT_ID);
+	}
+	
+	public Value callFunctionWorker(Value thisValue, String funcname, Value[] args, int isolateId) throws PlayerDebugException
+	{
+		Value retval = callPseudoFunction(thisValue, funcname, args, isolateId);
 		if (retval != null) {
 			return retval;
 		}
 
-		return callFunction(thisValue, false, funcname, args);
+		return callFunction(thisValue, false, funcname, args, isolateId);
 	}
 
 	/**
@@ -1423,10 +1438,10 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 * $obj(), and if so, handles that directly rather than calling the player.  Returns
 	 * null if the function being called is not a pseudofunction.
 	 */
-	private Value callPseudoFunction(Value thisValue, String funcname, Value[] args) throws PlayerDebugException{
+	private Value callPseudoFunction(Value thisValue, String funcname, Value[] args, int isolateId) throws PlayerDebugException{
 		if (thisValue.getType() == VariableType.UNDEFINED || thisValue.getType() == VariableType.NULL) {
 			if ("$obj".equals(funcname)) { //$NON-NLS-1$
-				return callObjPseudoFunction(args);
+				return callObjPseudoFunction(args, isolateId);
 			}
 		}
 
@@ -1437,25 +1452,30 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 * Handles a call to the debugger pseudofunction $obj() -- e.g. $obj(1234) returns
 	 * a pointer to the object with id 1234.
 	 */
-	private Value callObjPseudoFunction(Value[] args) throws PlayerDebugException {
+	private Value callObjPseudoFunction(Value[] args, int isolateId) throws PlayerDebugException {
 		if (args.length != 1) {
-			return DValue.forPrimitive(DValue.UNDEFINED);
+			return DValue.forPrimitive(DValue.UNDEFINED, isolateId);
 		}
 		double arg = ECMA.toNumber(this, args[0]);
 		long id = (long) arg;
 		if (id != arg) {
-			return DValue.forPrimitive(DValue.UNDEFINED);
+			return DValue.forPrimitive(DValue.UNDEFINED, isolateId);
 		}
-		DValue value = m_manager.getValue(id);
+		DValue value = m_manager.getValue(id, isolateId);
 		if (value == null) {
-			return DValue.forPrimitive(DValue.UNDEFINED);
+			return DValue.forPrimitive(DValue.UNDEFINED, isolateId);
 		}
 		return value;
 	}
 
 	public Value callConstructor(String funcname, Value[] args) throws PlayerDebugException
 	{
-		return callFunction(DValue.forPrimitive(null), true, funcname, args);
+		return callConstructorWorker(funcname, args, Isolate.DEFAULT_ID);
+	}
+	
+	public Value callConstructorWorker(String funcname, Value[] args, int isolateId) throws PlayerDebugException
+	{
+		return callFunction(DValue.forPrimitive(null, isolateId), true, funcname, args, isolateId);
 	}
 
 	private DMessage buildCallFunctionMessage(boolean isConstructor, Value thisValue, String funcname, Value[] args)
@@ -1504,17 +1524,19 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		return dm;
 	}
 
-	private void requestVariable(long id, String name, boolean fireGetter, boolean alsoGetChildren) throws NoResponseException, NotConnectedException, NotSuspendedException
+	private void requestVariable(long id, String name, boolean fireGetter, boolean alsoGetChildren, int isolateId) throws NoResponseException, NotConnectedException, NotSuspendedException
 	{
-		if (!isSuspended())
+		if (!isWorkerSuspended(isolateId))
 			throw new NotSuspendedException();
 
-		name = getRawMemberName(id, name);
+		name = getRawMemberName(id, name, isolateId);
 
 		DMessage dm = buildOutGetMessage(id, name, fireGetter, alsoGetChildren);
 
+		dm.setTargetIsolate(isolateId);
+		
 		// make sure any exception during the setter gets held onto
-		m_manager.beginPlayerCodeExecution();
+		m_manager.beginPlayerCodeExecution(isolateId);
 
 		int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT);
 		timeout += 500; // give the player enough time to raise its timeout exception
@@ -1522,7 +1544,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		boolean result = simpleRequestResponseMessage(dm, DMessage.InGetVariable, timeout);
 
 		// tell manager we're done; ignore returned FaultEvent
-		m_manager.endPlayerCodeExecution();
+		m_manager.endPlayerCodeExecution(isolateId);
 
 		if (!result)
 			throw new NoResponseException(timeout);
@@ -1559,9 +1581,9 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		return dm;
 	}
 
-	public FaultEvent setScalarMember(long varId, String memberName, int type, String value) throws NotSuspendedException, NoResponseException, NotConnectedException
+	public FaultEvent setScalarMember(long varId, String memberName, int type, String value, int isolateId) throws NotSuspendedException, NoResponseException, NotConnectedException
 	{
-		if (!isSuspended())
+		if (!isWorkerSuspended(isolateId))
 			throw new NotSuspendedException();
 
 		// If the varId is that of a stack frame, then we need to check whether that
@@ -1574,26 +1596,26 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		if (varId <= Value.BASE_ID && varId > Value.LEVEL_ID)
 		{
 			int depth = (int) (Value.BASE_ID - varId);
-			DStackContext context = m_manager.getFrame(depth);
+			DStackContext context = m_manager.getFrame(depth,isolateId);
 			DVariable activationObject = context.getActivationObject();
 			if (activationObject != null)
 				varId = activationObject.getValue().getId();
 		}
 
-		memberName = getRawMemberName(varId, memberName);
+		memberName = getRawMemberName(varId, memberName, isolateId);
 
 		// see if it is our any of our special variables
-		FaultEvent faultEvent = requestSetVariable( isPseudoVarId(varId) ? 0 : varId, memberName, type, value);
+		FaultEvent faultEvent = requestSetVariable( isPseudoVarId(varId) ? 0 : varId, memberName, type, value, isolateId);
 
 		// now that we sent it out, we need to clear our variable cache
 		// if it is our special context then mark the frame as stale.
-		if (isPseudoVarId(varId) && m_manager.getFrameCount() > 0)
+		if (isPseudoVarId(varId) && m_manager.getFrameCount(isolateId) > 0)
 		{
-			m_manager.getFrame(0).markStale();
+			m_manager.getFrame(0, isolateId).markStale();
 		}
 		else
 		{
-			DValue parent = m_manager.getValue(varId);
+			DValue parent = m_manager.getValue(varId,isolateId);
 			if (parent != null)
 				parent.removeAllMembers();
 		}
@@ -1624,11 +1646,11 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 * and second cases, we may need to fully resolve it so that the Player
 	 * will recognize it.
 	 */
-	private String getRawMemberName(long parentValueId, String memberName)
+	private String getRawMemberName(long parentValueId, String memberName, int isolateId)
 	{
 		if (memberName != null)
 		{
-			DValue parent = m_manager.getValue(parentValueId);
+			DValue parent = m_manager.getValue(parentValueId, isolateId);
 			if (parent != null)
 			{
 				int doubleColon = memberName.indexOf("::"); //$NON-NLS-1$
@@ -1644,19 +1666,20 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	/**
 	 * @return null for success, or fault event if a setter in the player threw an exception
 	 */
-	private FaultEvent requestSetVariable(long id, String name, int t, String value) throws NoResponseException
+	private FaultEvent requestSetVariable(long id, String name, int t, String value, int isolateId) throws NoResponseException
 	{
 		// convert type to typeName
 		String type = DVariable.typeNameFor(t);
 		DMessage dm = buildOutSetMessage(id, name, type, value);
+		dm.setTargetIsolate(isolateId);
 		FaultEvent faultEvent = null;
 //		System.out.println("setmsg id="+id+",name="+name+",t="+type+",value="+value);
 
 		// make sure any exception during the setter gets held onto
-		m_manager.beginPlayerCodeExecution();
+		m_manager.beginPlayerCodeExecution(isolateId);
 
 		// turn off squelch so we can hear the response
-		sendSquelch(false);
+		sendSquelch(false, isolateId);
 
 		int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT);
 
@@ -1664,13 +1687,13 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
 
 		// turn it back on
-		sendSquelch(true);
+		sendSquelch(true, isolateId);
 
 		// tell manager we're done, and get exception if any
-		faultEvent = m_manager.endPlayerCodeExecution();
+		faultEvent = m_manager.endPlayerCodeExecution(isolateId);
 
 		// hammer the variable cache and context array
-		m_manager.freeValueCache();
+		m_manager.freeValueCache(isolateId);
 		return faultEvent;
 	}
 
@@ -1729,21 +1752,22 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 	/**
 	 * Adds a watchpoint on the given expression
-	 * @throws NotConnectedException
-	 * @throws NoResponseException
-	 * @throws NotSupportedException
-	 * @throws NotSuspendedException
+	 * @throws flash.tools.debugger.NotConnectedException
+	 * @throws flash.tools.debugger.NoResponseException
+	 * @throws flash.tools.debugger.NotSupportedException
+	 * @throws flash.tools.debugger.NotSuspendedException
 	 */
-	public boolean addWatch(long varId, String varName, int type, int tag) throws NoResponseException, NotConnectedException, NotSupportedException
+	public boolean addWatch(long varId, String varName, int type, int tag, int isolateId) throws NoResponseException, NotConnectedException, NotSupportedException
 	{
 		// TODO check for NoResponse, NotConnected
 
-		if (!supportsWatchpoints())
+		if (!supportsWatchpoints(isolateId))
 			throw new NotSupportedException(PlayerSessionManager.getLocalizationManager().getLocalizedTextString("watchpointsNotSupported")); //$NON-NLS-1$
 
-		varName = getRawMemberName(varId, varName);
+		varName = getRawMemberName(varId, varName, isolateId);
 		DMessage dm = DMessageCache.alloc(4+DMessage.getSizeofPtr()+DMessage.getStringLength(varName)+1);
 		dm.setType(DMessage.OutAddWatch2);
+		dm.setTargetIsolate(isolateId);
 		dm.putPtr(varId);
 		try { dm.putString(varName); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); }
 		dm.putWord(type);
@@ -1756,13 +1780,13 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 	/**
 	 * Removes a watchpoint on the given expression
-	 * @throws NotConnectedException
-	 * @throws NoResponseException
-	 * @throws NotSuspendedException
+	 * @throws flash.tools.debugger.NotConnectedException
+	 * @throws flash.tools.debugger.NoResponseException
+	 * @throws flash.tools.debugger.NotSuspendedException
 	 */
-	public boolean removeWatch(long varId, String memberName) throws NoResponseException, NotConnectedException
+	public boolean removeWatch(long varId, String memberName, int isolateId) throws NoResponseException, NotConnectedException
 	{
-		memberName = getRawMemberName(varId, memberName);
+		memberName = getRawMemberName(varId, memberName, isolateId);
 		DMessage dm = DMessageCache.alloc(DMessage.getSizeofPtr()+DMessage.getStringLength(memberName)+1);
 		dm.setType(DMessage.OutRemoveWatch2);
 		dm.putPtr(varId);
@@ -1782,6 +1806,17 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		dm.setType(message);
 		sendMessage(dm);
 	}
+	
+	/**
+	 * Send a message that contains no data
+	 */
+	void sendMessageIsolate(int message, int isolateId)
+	{
+		DMessage dm = DMessageCache.alloc(0);
+		dm.setTargetIsolate(isolateId);
+		dm.setType(message);
+		sendMessage(dm);
+	}
 
 	/**
 	 * Send a fully formed message and release it when done
@@ -1790,6 +1825,26 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	{
 		try
 		{
+			if (dm.getType() != DMessage.OutSetActiveIsolate) {
+				int isolate = dm.getTargetIsolate();
+				if (isolate != getActiveIsolate().getId()) {
+					DMessage dm1 = DMessageCache.alloc(4);
+					dm1.setTargetIsolate(isolate);
+					dm1.setType(DMessage.OutSetActiveIsolate);
+					dm1.putDWord(isolate);
+
+					/* Use sendMessage here to avoid waiting for a response. 
+					 * The assumption is that once the message is sent, subsequent
+					 * messages are for that isolate regardless of the player confirming
+					 * it. With this change, performance has improved considerably; player
+					 * debugger has not gone out of sync since the ProcessTag messages
+					 * flood issue was resolved. */
+					sendMessage(dm1);
+
+					m_manager.setActiveIsolate(m_manager.getIsolate(isolate));
+
+				}
+			}
 			m_protocol.txMessage(dm);
 
 			if (m_debugMsgOn || m_debugMsgFileOn)
@@ -1806,15 +1861,15 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		DMessageCache.free(dm);
 	}
 
-
 	/**
 	 * Tell the player to shut-up
 	 */
-	boolean sendSquelch(boolean on)
+	boolean sendSquelch(boolean on, int isolateId)
 	{
 		boolean responded;
 		DMessage dm = DMessageCache.alloc(4);
 		dm.setType(DMessage.OutSetSquelch);
+		dm.setTargetIsolate(isolateId);
 		dm.putDWord( on ? 1 : 0);
 		responded = simpleRequestResponseMessage(dm, DMessage.InSquelch);
 		return responded;
@@ -1899,6 +1954,23 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 		sendOptionMessage(option, value);
 	}
+	
+	void sendConcurrentDebugger()
+	{
+		String option = "concurrent_debugger"; //$NON-NLS-1$
+		String value = "on"; //$NON-NLS-1$
+
+		sendOptionMessage(option, value);
+	}
+	
+	void sendWideLineDebugger()
+	{
+		String option = "wide_line_debugger"; //$NON-NLS-1$
+		String value = "on"; //$NON-NLS-1$
+
+		sendOptionMessage(option, value);
+		m_manager.setWideLines(true);
+	}
 
 	void sendOptionMessage(String option, String value)
 	{
@@ -1913,27 +1985,66 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 	public boolean supportsWatchpoints()
 	{
+		return supportsWatchpoints(Isolate.DEFAULT_ID);
+	}
+	
+	public boolean supportsWatchpoints(int isolateId)
+	{
 		if (m_playerSupportsWatchpoints == null)
-			m_playerSupportsWatchpoints = new Boolean(getOption("can_set_watchpoints", false)); //$NON-NLS-1$
+			m_playerSupportsWatchpoints = new Boolean(getOption("can_set_watchpoints", false, isolateId)); //$NON-NLS-1$
 		return m_playerSupportsWatchpoints.booleanValue();
 	}
 
 	public boolean playerCanBreakOnAllExceptions()
 	{
+		return playerCanBreakOnAllExceptions(Isolate.DEFAULT_ID);
+	}
+	
+	public boolean playerCanBreakOnAllExceptions(int isolateId)
+	{
 		if (m_playerCanBreakOnAllExceptions == null)
-			m_playerCanBreakOnAllExceptions = new Boolean(getOption("can_break_on_all_exceptions", false)); //$NON-NLS-1$
+			m_playerCanBreakOnAllExceptions = new Boolean(getOption("can_break_on_all_exceptions", false, isolateId)); //$NON-NLS-1$
 		return m_playerCanBreakOnAllExceptions.booleanValue();
 	}
+	
+	public boolean supportsConcurrency(int isolateId)
+	{
+		if (m_playerSupportsConcurrency == null)
+			m_playerSupportsConcurrency = new Boolean(getOption("concurrent_player", false, isolateId)); //$NON-NLS-1$
+		return m_playerSupportsConcurrency.booleanValue();
+	}
+	
+	public boolean supportsConcurrency()
+	{
+		return supportsConcurrency(Isolate.DEFAULT_ID);
+	}
+	
+	public boolean supportsWideLineNumbers()
+	{
+		return supportsWideLineNumbers(Isolate.DEFAULT_ID);
+	}
+	
+	public boolean supportsWideLineNumbers(int isolateId)
+	{
+		if (m_playerSupportsWideLine == null)
+			m_playerSupportsWideLine = new Boolean(getOption("wide_line_player", false, isolateId)); //$NON-NLS-1$
+		return m_playerSupportsWideLine.booleanValue();
+	}
 
 	public boolean playerCanTerminate()
 	{
-		return getOption("can_terminate", false); //$NON-NLS-1$
+		return getOption("can_terminate", false, Isolate.DEFAULT_ID); //$NON-NLS-1$
 	}
 
 	public boolean playerCanCallFunctions()
 	{
+		return playerCanCallFunctions(Isolate.DEFAULT_ID);
+	}
+	
+	public boolean playerCanCallFunctions(int isolateId)
+	{
 		if (m_playerCanCallFunctions == null)
-			m_playerCanCallFunctions = new Boolean(getOption("can_call_functions", false)); //$NON-NLS-1$
+			m_playerCanCallFunctions = new Boolean(getOption("can_call_functions", false, isolateId)); //$NON-NLS-1$
 		return m_playerCanCallFunctions.booleanValue();
 	}
 
@@ -1945,10 +2056,10 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 *            the name of the option
 	 * @return its value, or null
 	 */
-	public boolean getOption(String optionName, boolean defaultValue)
+	public boolean getOption(String optionName, boolean defaultValue, int isolateId)
 	{
 		boolean retval = defaultValue;
-		String optionValue = getOption(optionName, null);
+		String optionValue = getOption(optionName, null, isolateId);
 
 		if (optionValue != null)
 			retval = Boolean.valueOf(optionValue).booleanValue();
@@ -1964,19 +2075,38 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	 *            the name of the option
 	 * @return its value, or null
 	 */
-	public String getOption(String optionName, String defaultValue)
+	public String getOption(String optionName, String defaultValue, int isolateId)
 	{
 		String optionValue = defaultValue;
 
 		int msgSize = DMessage.getStringLength(optionName)+1;  // add 1 for trailing null of string
 
 		DMessage dm = DMessageCache.alloc(msgSize);
+		dm.setTargetIsolate(isolateId);
 		dm.setType(DMessage.OutGetOption);
 		try { dm.putString(optionName); } catch(UnsupportedEncodingException uee) { dm.putByte((byte)'\0'); }
 		if (simpleRequestResponseMessage(dm, DMessage.InOption))
 			optionValue = m_manager.getOption(optionName);
 		return optionValue;
 	}
+	
+	long getMessageInCount(DMessageCounter counter, long isolate, int msgType) {
+		if (isolate == Isolate.DEFAULT_ID) {
+			return counter.getInCount(msgType);
+		}
+		else {
+			return counter.getIsolateInCount(isolate, msgType);
+		}
+	}
+	
+	Object getMessageInLock(DMessageCounter counter, long isolate) {
+		if (isolate == Isolate.DEFAULT_ID) {
+			return counter.getInLock();
+		}
+		else {
+			return counter.getIsolateInLock(isolate);
+		}
+	}
 
 	/**
 	 * Send our message and assume that the next response that is received is
@@ -1989,12 +2119,15 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	{
 		boolean response = false;
 
+		//FIXME: Check if timeout needs to adjust to the isolate switching
+		// delay
 		// use default or user supplied timeout
 		timeout = (timeout > 0) ? timeout : getPreference(SessionManager.PREF_RESPONSE_TIMEOUT);
 
 		// note the number of messages of this type before our send
 		DMessageCounter msgCounter = getMessageCounter();
-		long num = msgCounter.getInCount(msgType);
+		int isolate = msg.getTargetIsolate();
+		long num = getMessageInCount(msgCounter, isolate, msgType);
 		long expect = num+1;
 
 		// send the message
@@ -2005,21 +2138,24 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 		// now wait till we see a message come in
 		m_incoming = false;
-		synchronized (msgCounter.getInLock())
+		synchronized (getMessageInLock(msgCounter, isolate))
 		{
-			while( (expect > msgCounter.getInCount(msgType)) &&
+			while( (expect > getMessageInCount(msgCounter, isolate, msgType)) &&
 					System.currentTimeMillis() < startTime + timeout &&
 					isConnected())
 			{
 				// block until the message counter tells us that some message has been received
 				try
 				{
-					msgCounter.getInLock().wait(timeout);
+					getMessageInLock(msgCounter, isolate).wait(timeout);
 				}
 				catch (InterruptedException e)
 				{
 					// this should never happen
 					e.printStackTrace();
+					//FIXME: Will resetting the interrupted status here
+					//cause any problems?
+//		            Thread.currentThread().interrupt();
 				}
 
 				// if we see incoming messages, then we should reset our timeout
@@ -2034,7 +2170,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 			}
 		}
 
-		if (msgCounter.getInCount(msgType) >= expect)
+		if (getMessageInCount(msgCounter, isolate, msgType) >= expect)
 			response = true;
 		else if (timeout <= 0 && Trace.error)
 			Trace.trace("Timed-out waiting for "+DMessage.inTypeName(msgType)+" response to message "+msg.outToString()); //$NON-NLS-1$ //$NON-NLS-2$
@@ -2047,8 +2183,31 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 	// use default timeout
 	boolean simpleRequestResponseMessage(DMessage msg, int msgType) 	{ return simpleRequestResponseMessage(msg, msgType, -1); 	}
+	
+	boolean simpleRequestResponseMessageIsolate(DMessage msg, int msgType, int isolateId) 	{ 
+		return simpleRequestResponseMessageIsolate(msg, msgType, -1, isolateId); 			
+	}
+	
+	boolean simpleRequestResponseMessageIsolate(DMessage msg, int msgType, int timeout, int isolateId)
+	{
+		msg.setTargetIsolate(isolateId);
+		return simpleRequestResponseMessage(msg, msgType, timeout);
+	}
+	
 	boolean simpleRequestResponseMessage(int msg, int msgType)			{ return simpleRequestResponseMessage(msg, msgType, -1); 	}
+	
+	boolean simpleRequestResponseMessageIsolate(int msg, int msgType, int isolateId) { 
+		return simpleRequestResponseMessageIsolate(msg, msgType, -1, isolateId);
+	}
 
+	boolean simpleRequestResponseMessageIsolate(int msg, int msgType, int timeout, int isolateId)
+	{
+		DMessage dm = DMessageCache.alloc(0);
+		dm.setType(msg);
+		dm.setTargetIsolate(isolateId);
+		return simpleRequestResponseMessage(dm, msgType, timeout);
+	}
+	
 	// Convenience function
 	boolean simpleRequestResponseMessage(int msg, int msgType, int timeout)
 	{
@@ -2096,6 +2255,12 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	{
 		switch (msg.getType())
 		{
+		case DMessage.InIsolate:
+
+				m_lastPreIsolate = (int)msg.getDWord();
+			
+			break;
+		
 			case DMessage.InAskBreakpoints:
 			case DMessage.InBreakAt:
 			case DMessage.InBreakAtExt:
@@ -2105,7 +2270,10 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 				// event queue, which the host debugger may immediately process;
 				// if the debugger calls back to the Session, the Session must be
 				// correctly marked as halted.
-				m_isHalted = true;
+				if (m_lastPreIsolate == Isolate.DEFAULT_ID)
+					m_isHalted = true;
+				else
+					updateHaltIsolateStatus(m_lastPreIsolate, true);
 				break;
 			}
 		}
@@ -2132,23 +2300,31 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 			case DMessage.InProcessTag:
 			{
 				// need to send a response to this message to keep the player going
-				sendMessage(DMessage.OutProcessedTag);
+				sendMessageIsolate(DMessage.OutProcessedTag, msg.getTargetIsolate());
 				break;
 			}
 
 			case DMessage.InContinue:
 			{
-				m_isHalted = false;
+				if (msg.getTargetIsolate() == Isolate.DEFAULT_ID)
+					m_isHalted = false;
+				else {
+					updateHaltIsolateStatus(msg.getTargetIsolate(), false);
+				}
 				break;
 			}
 
 			case DMessage.InOption:
 			{
-				String s = msg.getString();
-				String v = msg.getString();
-
-				// add it to our properties, for DEBUG purposes only
-				m_prefs.put(s, v);
+				//workers inherit options, so only store options
+				//from main thread.
+				if (msg.getTargetIsolate() == Isolate.DEFAULT_ID) {
+					String s = msg.getString();
+					String v = msg.getString();
+
+					// add it to our properties, for DEBUG purposes only
+					m_prefs.put(s, v);
+				}
 				break;
 			}
 
@@ -2156,7 +2332,12 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 			case DMessage.InScript:
 			case DMessage.InRemoveScript:
 			{
+				//FIXME: Clear this cache only for affected
+				//workers. Right now, the key contains worker
+				//id, so we are safe. But we unnecessarily flush
+				//the queue.
 				m_evalIsAndInstanceofCache.clear();
+				
 				m_incoming = true;
 				break;
 			}
@@ -2179,7 +2360,18 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		m_lastResponse = true;
 	}
 
-    /**
+    private void updateHaltIsolateStatus(int targetIsolate, boolean value) {
+    	if (!m_isolateStatus.containsKey(targetIsolate)) {
+    		PlayerSessionIsolateStatus status = new PlayerSessionIsolateStatus();
+    		status.m_isHalted = value;
+    		m_isolateStatus.put(targetIsolate, status);    		
+    	}
+    	else {
+    		m_isolateStatus.get(targetIsolate).m_isHalted = value;
+    	}
+	}
+
+	/**
      * A background thread which wakes up periodically and fetches the SWF and SWD
      * from the Player for new movies that have loaded.  It then uses these to create
 	 * an instance of MovieMetaData (a class shared with the Profiler) from which
@@ -2191,108 +2383,114 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
     public void run()
     {
     	long last = 0;
-		while(isConnected())
-		{
-			// try every 250ms
-			try { Thread.sleep(250); } catch(InterruptedException ie) {}
-
-			try
-			{
-				// let's make sure that the traffic level is low before
-				// we do our requests.
-				long current = m_protocol.messagesReceived();
-				long delta = last - current;
-				last = current;
-
-				// if the last message that went out was not responded to
-				// or we are not suspended and have high traffic
-				// then wait for later.
-				if (!m_lastResponse || (!isSuspended() && delta > 5))
-					throw new NotSuspendedException();
-
-				// we are either suspended or low enough traffic
-
-				// get the list of swfs we have
-				int count = m_manager.getSwfInfoCount();
-				for(int i=0; i<count; i++)
-				{
-					DSwfInfo info = m_manager.getSwfInfo(i);
-
-					// no need to process if it's been removed
-					if (info == null || info.isUnloaded() || info.isPopulated() || (info.getVmVersion() > 0) )
-						continue;
-
-					// see if the swd has been loaded, throws exception if unable to load it.
-					// Also triggers a callback into the info object to freshen its contents
-					// if successful
-					info.getSwdSize(this);
-
-                    // check since our vm version info could get updated in between.
-                    if (info.getVmVersion() > 0)
-                    {
-                        // mark it populated if we haven't already done so
-                        info.setPopulated();
-                        continue;
-                    }
-
-					// so by this point we know that we've got good swd data,
-					// or we've made too many attempts and gave up.
-					if (!info.isSwdLoading() && !info.isUnloaded())
-					{
-						// now load the swf, if we haven't already got it
-						if (info.getSwf() == null && !info.isUnloaded())
-							info.setSwf(requestSwf(i));
-
-						// only get the swd if we haven't got it
-						if (info.getSwd() == null && !info.isUnloaded())
-							info.setSwd(requestSwd(i));
-
-						try
-						{
-							// now go populate the functions tables...
-							if (!info.isUnloaded())
-								info.parseSwfSwd(m_manager);
-						}
-						catch(Throwable e)
-						{
-							// oh this is not good and means that we should probably
-							// give up.
-							if (Trace.error)
-							{
-								Trace.trace("Error while parsing swf/swd '"+info.getUrl()+"'. Giving up and marking it processed"); //$NON-NLS-1$ //$NON-NLS-2$
-								e.printStackTrace();
-							}
-
-							info.setPopulated();
-						}
-					}
-				}
-			}
-			catch(InProgressException ipe)
-			{
-				// swd is still loading so give us a bit of
-				// time and then come back and try again
-			}
-			catch(NoResponseException nre)
-			{
-				// timed out on one of our requests so don't bother
-				// continuing right now,  try again later
-			}
-			catch(NotSuspendedException nse)
-			{
-				// probably want to wait until we are halted before
-				// doing this heavy action
-			}
-			catch(Exception e)
-			{
-				// maybe not good
-				if (Trace.error)
-				{
-					Trace.trace("Exception in background swf/swd processing thread"); //$NON-NLS-1$
-					e.printStackTrace();
-				}
-			}
-		}
+    	while(isConnected())
+    	{
+    		// try every 250ms
+    		try { Thread.sleep(250); } catch(InterruptedException ie) {}
+
+    		try
+    		{
+    			// let's make sure that the traffic level is low before
+    			// we do our requests.
+    			long current = m_protocol.messagesReceived();
+    			long delta = last - current;
+    			last = current;
+
+    			// if the last message that went out was not responded to
+    			// or we are not suspended and have high traffic
+    			// then wait for later.
+    			if (!m_lastResponse || (!isSuspended() && delta > 5))
+    				throw new NotSuspendedException();
+
+    			// we are either suspended or low enough traffic
+
+    			// get the list of swfs we have
+    			for (Isolate isolate : m_manager.getIsolates()) {
+    				int isolateId = isolate.getId();
+    				if (isolateId != Isolate.DEFAULT_ID && !isWorkerSuspended(isolateId) && delta > 5) {
+    					throw new NotSuspendedException();
+    				}
+    				int count = m_manager.getSwfInfoCount(isolateId);
+    				for(int i=0; i<count; i++)
+    				{
+    					DSwfInfo info = m_manager.getSwfInfo(i, isolateId);
+
+    					// no need to process if it's been removed
+    					if (info == null || info.isUnloaded() || info.isPopulated() || (info.getVmVersion() > 0) )
+    						continue;
+
+    					// see if the swd has been loaded, throws exception if unable to load it.
+    					// Also triggers a callback into the info object to freshen its contents
+    					// if successful
+    					//FIXME: remove sysout
+    					info.getSwdSize(this);
+    					// check since our vm version info could get updated in between.
+    					if (info.getVmVersion() > 0)
+    					{
+    						// mark it populated if we haven't already done so
+    						info.setPopulated();
+    						continue;
+    					}
+
+    					// so by this point we know that we've got good swd data,
+    					// or we've made too many attempts and gave up.
+    					if (!info.isSwdLoading() && !info.isUnloaded())
+    					{
+    						// now load the swf, if we haven't already got it
+    						if (info.getSwf() == null && !info.isUnloaded())
+    							info.setSwf(requestSwf(i));
+
+    						// only get the swd if we haven't got it
+    						if (info.getSwd() == null && !info.isUnloaded())
+    							info.setSwd(requestSwd(i));
+
+    						try
+    						{
+    							// now go populate the functions tables...
+    							if (!info.isUnloaded())
+    								info.parseSwfSwd(m_manager);
+    						}
+    						catch(Throwable e)
+    						{
+    							// oh this is not good and means that we should probably
+    							// give up.
+    							if (Trace.error)
+    							{
+    								Trace.trace("Error while parsing swf/swd '"+info.getUrl()+"'. Giving up and marking it processed"); //$NON-NLS-1$ //$NON-NLS-2$
+    								e.printStackTrace();
+    							}
+
+    							info.setPopulated();
+    						}
+    					}
+    				}
+    			}
+    		}
+    		catch(InProgressException ipe)
+    		{
+    			// swd is still loading so give us a bit of
+    			// time and then come back and try again
+    		}
+    		catch(NoResponseException nre)
+    		{
+    			// timed out on one of our requests so don't bother
+    			// continuing right now,  try again later
+    		}
+    		catch(NotSuspendedException nse)
+    		{
+    			// probably want to wait until we are halted before
+    			// doing this heavy action
+    		}
+    		catch(Exception e)
+    		{
+    			// maybe not good
+    			if (Trace.error)
+    			{
+    				Trace.trace("Exception in background swf/swd processing thread"); //$NON-NLS-1$
+    				e.printStackTrace();
+    			}
+    		}
+    	}
     }
 
 	byte[] requestSwf(int index) throws NoResponseException
@@ -2341,8 +2539,9 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	{
 		try
 		{
-			if (m_debugMsgOn)
+			if (m_debugMsgOn) {
 				System.out.println( (in) ? dm.inToString(m_debugMsgSize) : dm.outToString(m_debugMsgSize) );
+			}
 
 			if (m_debugMsgFileOn)
 			{
@@ -2356,6 +2555,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 	// i/o for tracing
     java.io.Writer m_trace;
+	
 
 	java.io.Writer traceFile() throws IOException
 	{
@@ -2369,7 +2569,7 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 				// java properties dump
 				java.util.Properties props = System.getProperties();
-				props.list(new java.io.PrintWriter(m_trace));
+				props.list(new PrintWriter(m_trace));
 
 				m_trace.write(s_newline);
 
@@ -2403,61 +2603,90 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 	}
 
 	public void breakOnCaughtExceptions(boolean b) throws NotSupportedException, NoResponseException {
-		if (!playerCanBreakOnAllExceptions())
+		breakOnCaughtExceptions(b, Isolate.DEFAULT_ID);
+	}
+	
+	public void breakOnCaughtExceptions(boolean b, int isolateId) throws NotSupportedException, NoResponseException {
+		if (!playerCanBreakOnAllExceptions(isolateId))
 			throw new NotSupportedException(PlayerSessionManager.getLocalizationManager().getLocalizedTextString("exceptionBreakpointsNotSupported")); //$NON-NLS-1$
 
 		DMessage dm = DMessageCache.alloc(1);
 		dm.setType(DMessage.OutPassAllExceptionsToDebugger);
 		dm.putByte((byte)(b ? 1 : 0));
-		sendMessage(dm);
+		dm.setTargetIsolate(isolateId);
+		/* TODO: Verify that sendMessage below is a bug */
+//		sendMessage(dm);
 		if (!simpleRequestResponseMessage(dm, DMessage.InPassAllExceptionsToDebugger))
 			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
 	}
 
+
 	public boolean evalIs(Value value, Value type) throws PlayerDebugException, PlayerFaultException
 	{
-		return evalIsOrInstanceof(BinaryOp.Is, value, type);
+		return evalIsOrInstanceof(BinaryOp.Is, value, type, Isolate.DEFAULT_ID);
 	}
 
 	public boolean evalIs(Value value, String type) throws PlayerDebugException, PlayerFaultException
 	{
-		return evalIsOrInstanceof(BinaryOp.Is, value, type);
+		return evalIsOrInstanceof(BinaryOp.Is, value, type, Isolate.DEFAULT_ID);
 	}
 
 	public boolean evalInstanceof(Value value, Value type) throws PlayerDebugException, PlayerFaultException
 	{
-		return evalIsOrInstanceof(BinaryOp.Instanceof, value, type);
+		return evalIsOrInstanceof(BinaryOp.Instanceof, value, type, Isolate.DEFAULT_ID);
 	}
 
 	public boolean evalInstanceof(Value value, String type) throws PlayerDebugException, PlayerFaultException
 	{
-		return evalIsOrInstanceof(BinaryOp.Instanceof, value, type);
+		return evalIsOrInstanceof(BinaryOp.Instanceof, value, type, Isolate.DEFAULT_ID);
+	}
+	
+	// isolate version
+	
+	public boolean evalIsWorker(Value value, Value type, int isolateId) throws PlayerDebugException, PlayerFaultException
+	{
+		return evalIsOrInstanceof(BinaryOp.Is, value, type, isolateId);
 	}
 
-	private boolean evalIsOrInstanceof(BinaryOp op, Value value, Value type) throws PlayerDebugException, PlayerFaultException
+	public boolean evalIsWorker(Value value, String type, int isolateId) throws PlayerDebugException, PlayerFaultException
 	{
-		String key = value.getTypeName() + " " + op + " " + type.getTypeName(); //$NON-NLS-1$ //$NON-NLS-2$
+		return evalIsOrInstanceof(BinaryOp.Is, value, type, isolateId);
+	}
+
+	public boolean evalInstanceofWorker(Value value, Value type, int isolateId) throws PlayerDebugException, PlayerFaultException
+	{
+		return evalIsOrInstanceof(BinaryOp.Instanceof, value, type, isolateId);
+	}
+
+	public boolean evalInstanceofWorker(Value value, String type, int isolateId) throws PlayerDebugException, PlayerFaultException
+	{
+		return evalIsOrInstanceof(BinaryOp.Instanceof, value, type, isolateId);
+	}
+
+	private boolean evalIsOrInstanceof(BinaryOp op, Value value, Value type, int isolateId) throws PlayerDebugException, PlayerFaultException
+	{
+		String key = value.getTypeName() + " " + op + " " + type.getTypeName() + " " + String.valueOf(isolateId); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 		Boolean retval = m_evalIsAndInstanceofCache.get(key);
 		if (retval == null)
 		{
-			retval = new Boolean(ECMA.toBoolean(evalBinaryOp(op, value, type)));
+			retval = new Boolean(ECMA.toBoolean(evalBinaryOp(op, value, type, isolateId)));
 			m_evalIsAndInstanceofCache.put(key, retval);
 		}
 
 		return retval.booleanValue();
 	}
 
-	private boolean evalIsOrInstanceof(BinaryOp op, Value value, String type) throws PlayerDebugException, PlayerFaultException
+	private boolean evalIsOrInstanceof(BinaryOp op, Value value, String type, int isolateId) throws PlayerDebugException, PlayerFaultException
 	{
-		String key = value.getTypeName() + " " + op + " " + type; //$NON-NLS-1$ //$NON-NLS-2$
+		String key = value.getTypeName() + " " + op + " " + type + " " + String.valueOf(isolateId); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 		Boolean retval = m_evalIsAndInstanceofCache.get(key);
 		if (retval == null)
 		{
-			Value typeval = getGlobal(type);
+			Value typeval = getGlobalWorker(type, isolateId);
 			if (typeval == null)
 				retval = Boolean.FALSE;
 			else
-				retval = new Boolean(ECMA.toBoolean(evalBinaryOp(op, value, typeval)));
+				retval = new Boolean(ECMA.toBoolean(evalBinaryOp(op, value, typeval, isolateId)));
 			m_evalIsAndInstanceofCache.put(key, retval);
 		}
 
@@ -2466,19 +2695,19 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 
 	public boolean evalIn(Value property, Value object) throws PlayerDebugException, PlayerFaultException
 	{
-		return ECMA.toBoolean(evalBinaryOp(BinaryOp.In, property, object));
+		return ECMA.toBoolean(evalBinaryOp(BinaryOp.In, property, object, Isolate.DEFAULT_ID));
 	}
 
 	public Value evalAs(Value value, Value type) throws PlayerDebugException, PlayerFaultException {
-		return evalBinaryOp(BinaryOp.As, value, type);
+		return evalBinaryOp(BinaryOp.As, value, type, Isolate.DEFAULT_ID);
 	}
 
-	private Value evalBinaryOp(BinaryOp op, Value lhs, Value rhs) throws PlayerDebugException, PlayerFaultException
+	private Value evalBinaryOp(BinaryOp op, Value lhs, Value rhs, int isolateId) throws PlayerDebugException, PlayerFaultException
 	{
-		if (!isSuspended())
+		if (!isWorkerSuspended(isolateId))
 			throw new NotSuspendedException();
 
-		if (!playerCanCallFunctions())
+		if (!playerCanCallFunctions(isolateId))
 		{
 			Map<String,String> parameters = new HashMap<String,String>();
 			parameters.put("operator", op.getName()); //$NON-NLS-1$
@@ -2489,10 +2718,11 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		int id = (int) (Math.random() * 65536); // good 'nuff
 		DMessage dm = buildBinaryOpMessage(id, op, lhs, rhs);
 
-		m_manager.clearLastBinaryOp();
+		dm.setTargetIsolate(isolateId);
+		m_manager.clearLastBinaryOp(isolateId);
 
 		// make sure any exception gets held onto
-		m_manager.beginPlayerCodeExecution();
+		m_manager.beginPlayerCodeExecution(isolateId);
 
 		// TODO wrong timeout
 		int timeout = getPreference(SessionManager.PREF_GETVAR_RESPONSE_TIMEOUT);
@@ -2501,20 +2731,20 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		boolean result = simpleRequestResponseMessage(dm, DMessage.InBinaryOp, timeout);
 
 		// tell manager we're done; ignore returned FaultEvent
-		m_manager.endPlayerCodeExecution();
+		m_manager.endPlayerCodeExecution(isolateId);
 
 		if (!result)
 			throw new NoResponseException(timeout);
 
-		DVariable lastBinaryOp = m_manager.lastBinaryOp();
+		DVariable lastBinaryOp = m_manager.lastBinaryOp(isolateId);
 		Value v;
 		if (lastBinaryOp != null)
 			v = lastBinaryOp.getValue();
 		else
-			v = DValue.forPrimitive(Value.UNDEFINED);
+			v = DValue.forPrimitive(Value.UNDEFINED, isolateId);
 
 		if (v.isAttributeSet(ValueAttribute.IS_EXCEPTION))
-			throw new PlayerFaultException(new ExceptionFault(v.getValueAsString(), false, v));
+			throw new PlayerFaultException(new ExceptionFault(v.getValueAsString(), false, v, isolateId));
 
 		return v;
 	}
@@ -2560,4 +2790,280 @@ public class PlayerSession implements Session, DProtocolNotifierIF, Runnable
 		return null;
 	}
 
+	/* (non-Javadoc)
+	 * @see flash.tools.debugger.Session#refreshIsolates()
+	 */
+	public Isolate[] refreshWorkers() throws NotSupportedException,
+			NotSuspendedException, NoResponseException, NotConnectedException {
+		if (!supportsConcurrency()) {
+			throw new NotSupportedException(PlayerSessionManager.getLocalizationManager().getLocalizedTextString("concurrencyNotSupported")); //$NON-NLS-1$
+		}
+		if (!isSuspended())
+			throw new NotSuspendedException();
+		
+		boolean response = simpleRequestResponseMessage(DMessage.OutIsolateEnumerate, DMessage.InIsolateEnumerate);
+		
+		if (response) {
+			return m_manager.getIsolates();
+		}
+		return null;
+	}
+
+	private Isolate getActiveIsolate() {
+		return m_manager.getActiveIsolate();
+	}
+
+	@Override
+	public Isolate[] getWorkers() {
+		return m_manager.getIsolates();
+	}
+
+	@Override
+	public void resumeWorker(int isolateId) throws NotSuspendedException,
+			NotConnectedException, NoResponseException {
+		if (!isWorkerSuspended(isolateId))
+			throw new NotSuspendedException();
+
+		if (!simpleRequestResponseMessageIsolate(DMessage.OutContinue, DMessage.InContinue, isolateId))
+			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+	}
+
+	@Override
+	public int suspendReasonWorker(int isolateId) throws NotConnectedException {
+		DSuspendInfo info = getSuspendInfoIsolate(isolateId);
+		return info.getReason();
+	}
+	
+	public DSuspendInfo getSuspendInfoIsolate(int isolateId)
+	{
+		DSuspendInfo info = m_manager.getSuspendInfo(isolateId);
+		if (info == null)
+		{
+			if (simpleRequestResponseMessageIsolate(DMessage.OutGetBreakReason, DMessage.InBreakReason, isolateId))
+				info = m_manager.getSuspendInfo(isolateId);
+
+			// if we still can't get any info from the manager...
+			if (info == null)
+				info = new DSuspendInfo();  // empty unknown break information
+		}
+		return info;
+	}
+
+	@Override
+	public void stepContinueWorker(int isolateId)
+			throws NotSuspendedException, NoResponseException,
+			NotConnectedException {
+		if (!isWorkerSuspended(isolateId))
+			throw new NotSuspendedException();
+
+		// send a step-continue message and then wait for the Flash player to tell us that is has
+		// resumed execution
+		if (!simpleRequestResponseMessageIsolate(DMessage.OutStepContinue, DMessage.InContinue, isolateId))
+			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+	}
+
+	@Override
+	public Location setBreakpointWorker(int fileId, int lineNum, int isolateId)
+			throws NoResponseException, NotConnectedException {
+		/* send the message to the player and await a response */
+		Location l = null;
+		int bp = DLocation.encodeId(fileId, lineNum);
+		int wideLineSize = 0;
+		if (supportsWideLineNumbers())
+			wideLineSize = 4;
+		DMessage dm = DMessageCache.alloc(8 + wideLineSize);
+		dm.setType(DMessage.OutSetBreakpoints);
+		dm.putDWord(1);
+		if (!supportsWideLineNumbers())
+			dm.putDWord(bp);
+		else {
+			dm.putDWord(fileId);
+			dm.putDWord(lineNum);
+		}
+
+		boolean gotResponse = simpleRequestResponseMessageIsolate(dm, DMessage.InSetBreakpoint, isolateId);
+		if(gotResponse)
+		{
+			/* even though we think we got an answer check that the breakpoint was added */
+			l = m_manager.getBreakpoint(bp, isolateId);
+		}
+		else
+			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+
+		return l;
+	}
+
+	@Override
+	public Frame[] getFramesWorker(int isolateId) throws NotConnectedException {
+		return m_manager.getFrames(isolateId);		
+	}
+
+	@Override
+	public SwfInfo[] getSwfsWorker(int isolateId) throws NoResponseException {
+		int swfCount = 0;
+		swfCount = m_manager.getSwfInfoCount(isolateId);
+		if (swfCount == 0)
+		{
+			// need to help out on the first one since the player
+			// doesn't send it
+			requestSwfInfo(0, isolateId);
+		}
+		//SwfInfo[] swfs = m_manager.getSwfInfos();
+		
+		ArrayList<SwfInfo> swfList = new ArrayList<SwfInfo>(); 
+
+		for ( SwfInfo info : m_manager.getSwfInfos(isolateId) ) {
+			swfList.add(info);
+		}
+
+		return swfList.toArray(new SwfInfo[0]);
+	}
+
+	@Override
+	public void stepIntoWorker(int isolateId) throws NotSuspendedException,
+			NoResponseException, NotConnectedException {
+		if (isWorkerSuspended(isolateId))
+		{
+			// send a step-into message and then wait for the Flash player to tell us that is has
+			// resumed execution
+			if (!simpleRequestResponseMessageIsolate(DMessage.OutStepInto, DMessage.InContinue, isolateId))
+				throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+		}
+		else
+			throw new NotSuspendedException();
+		
+	}
+
+	@Override
+	public void stepOutWorker(int isolateId) throws NotSuspendedException,
+			NoResponseException, NotConnectedException {
+		if (isWorkerSuspended(isolateId))
+		{
+			// send a step-out message and then wait for the Flash player to tell us that is has
+			// resumed execution
+			if (!simpleRequestResponseMessageIsolate(DMessage.OutStepOut, DMessage.InContinue, isolateId))
+				throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+		}
+		else
+			throw new NotSuspendedException();
+		
+	}
+
+	@Override
+	public void stepOverWorker(int isolateId) throws NotSuspendedException,
+			NoResponseException, NotConnectedException {
+		if (isWorkerSuspended(isolateId))
+		{
+			// send a step-over message and then wait for the Flash player to tell us that is has
+			// resumed execution
+			if (!simpleRequestResponseMessageIsolate(DMessage.OutStepOver, DMessage.InContinue, isolateId))
+				throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+		}
+		else
+			throw new NotSuspendedException();
+		
+	}
+
+	public boolean evalInWorker(Value property, Value object, int isolateId) throws PlayerDebugException, PlayerFaultException
+	{
+		return ECMA.toBoolean(evalBinaryOp(BinaryOp.In, property, object, isolateId));
+	}
+
+	public Value evalAsWorker(Value value, Value type, int isolateId) throws PlayerDebugException, PlayerFaultException {
+		return evalBinaryOp(BinaryOp.As, value, type, isolateId);
+	}
+
+	@Override
+	public void suspendWorker(int isolateId) throws SuspendedException,
+			NotConnectedException, NoResponseException {
+		// send a halt message
+		int wait = getPreference(SessionManager.PREF_SUSPEND_WAIT);
+ 		int every = 50; // wait this long for a response.  The lower the number the more aggressive we are!
+
+		if (isWorkerSuspended(isolateId))
+			throw new SuspendedException();
+
+		while (!isWorkerSuspended(isolateId) && wait > 0)
+		{
+			simpleRequestResponseMessageIsolate(DMessage.OutStopDebug, DMessage.InBreakAtExt, every, isolateId);
+			wait -= every;
+		}
+
+		if (!isWorkerSuspended(isolateId))
+			throw new NoResponseException(wait);	
+	}
+
+	@Override
+	public IsolateSession getWorkerSession(int isolateId) {
+		if (m_isolateSessions.containsKey(isolateId)) {
+			return m_isolateSessions.get(isolateId);
+		}
+		else {
+			IsolateSession workerSession = new IsolatePlayerSession(isolateId, this);
+			m_isolateSessions.put(isolateId, workerSession);
+			return workerSession;
+		}
+		
+	}
+	
+	public boolean setExceptionBreakpoint(String exceptionClass) throws NoResponseException, NotConnectedException {
+		return setExceptionBreakpointWorker(exceptionClass, Isolate.DEFAULT_ID);
+	}
+	
+	public boolean setExceptionBreakpointWorker(String exceptionClass, int isolateId) throws NoResponseException, NotConnectedException {
+		int messageSize = DMessage.getStringLength(exceptionClass) + 1;
+		
+		DMessage dm = DMessageCache.alloc(messageSize);
+		dm.setType(DMessage.OutSetExceptionBreakpoint);
+		dm.setTargetIsolate(isolateId);
+		try {
+			dm.putString(exceptionClass);
+		} catch (UnsupportedEncodingException e) {
+			// couldn't write out the string, so just terminate it and complete anyway
+			dm.putByte((byte)'\0');
+		}
+
+		boolean gotResponse = simpleRequestResponseMessageIsolate(dm, DMessage.InSetExceptionBreakpoint, isolateId);
+		if(gotResponse)
+		{
+			return true;
+		}
+		else
+			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+
+	}
+	
+	@Override
+	public boolean clearExceptionBreakpoint(String exceptionClass) throws NoResponseException, NotConnectedException {
+		return clearExceptionBreakpointWorker(exceptionClass, Isolate.DEFAULT_ID);
+	}
+
+	@Override
+	public boolean clearExceptionBreakpointWorker(String exceptionClass, int isolateId) throws NoResponseException, NotConnectedException {
+		int messageSize = DMessage.getStringLength(exceptionClass) + 1;
+		DMessage dm = DMessageCache.alloc(messageSize);
+		dm.setType(DMessage.OutRemoveExceptionBreakpoint);
+		dm.setTargetIsolate(isolateId);
+		try {
+			dm.putString(exceptionClass);
+		} catch (UnsupportedEncodingException e) {
+			// couldn't write out the string, so just terminate it and complete anyway
+			dm.putByte((byte)'\0');
+		}
+
+		boolean gotResponse = simpleRequestResponseMessageIsolate(dm, DMessage.InRemoveExceptionBreakpoint, isolateId);
+		if(gotResponse)
+		{
+			return true;
+		}
+		else
+			throw new NoResponseException(getPreference(SessionManager.PREF_RESPONSE_TIMEOUT));
+
+	}
+
+	@Override
+	public void setLauncher(ILauncher launcher) {
+		this.launcher = launcher;
+	}
+
 }

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/379cb609/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSessionIsolateStatus.java
----------------------------------------------------------------------
diff --git a/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSessionIsolateStatus.java b/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSessionIsolateStatus.java
new file mode 100644
index 0000000..96700cb
--- /dev/null
+++ b/modules/debugger/src/java/flash/tools/debugger/concrete/PlayerSessionIsolateStatus.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package flash.tools.debugger.concrete;
+
+public class PlayerSessionIsolateStatus {
+
+	/**
+	 * Corresponding to playersession::m_isHalted, but for isolate.
+	 */
+	public boolean m_isHalted;
+}

http://git-wip-us.apache.org/repos/asf/flex-sdk/blob/379cb609/modules/debugger/src/java/flash/tools/debugger/events/BreakEvent.java
----------------------------------------------------------------------
diff --git a/modules/debugger/src/java/flash/tools/debugger/events/BreakEvent.java b/modules/debugger/src/java/flash/tools/debugger/events/BreakEvent.java
index 7436434..7a88fc0 100644
--- a/modules/debugger/src/java/flash/tools/debugger/events/BreakEvent.java
+++ b/modules/debugger/src/java/flash/tools/debugger/events/BreakEvent.java
@@ -1,24 +1,24 @@
 /*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
  *
- *  Licensed to the Apache Software Foundation (ASF) under one or more
- *  contributor license agreements.  See the NOTICE file distributed with
- *  this work for additional information regarding copyright ownership.
- *  The ASF licenses this file to You under the Apache License, Version 2.0
- *  (the "License"); you may not use this file except in compliance with
- *  the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 
 package flash.tools.debugger.events;
 
+import flash.tools.debugger.Isolate;
+
 /**
  * Break event is received when the player halts execution
  */
@@ -29,10 +29,19 @@ public class BreakEvent extends DebugEvent
 
 	/** line number in the source file where the Player has suspended. */
 	public int line;
+	
+	public int isolateId;
 
 	public BreakEvent(int fId, int l)
 	{
 		fileId = fId;
 		line = l;
+		isolateId = Isolate.DEFAULT_ID;
+	}
+	
+	public BreakEvent(int fId, int l, int isolate)
+	{
+		this(fId, l);
+		isolateId = isolate;
 	}
 }