environment.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /* -*- indent-tabs-mode: nil; js-indent-level: 2; js-indent-level: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. "use strict";
  6. const { ActorClassWithSpec } = require("devtools/shared/protocol");
  7. const { createValueGrip } = require("devtools/server/actors/object");
  8. const { environmentSpec } = require("devtools/shared/specs/environment");
  9. /**
  10. * Creates an EnvironmentActor. EnvironmentActors are responsible for listing
  11. * the bindings introduced by a lexical environment and assigning new values to
  12. * those identifier bindings.
  13. *
  14. * @param Debugger.Environment aEnvironment
  15. * The lexical environment that will be used to create the actor.
  16. * @param ThreadActor aThreadActor
  17. * The parent thread actor that contains this environment.
  18. */
  19. let EnvironmentActor = ActorClassWithSpec(environmentSpec, {
  20. initialize: function (environment, threadActor) {
  21. this.obj = environment;
  22. this.threadActor = threadActor;
  23. },
  24. /**
  25. * Return an environment form for use in a protocol message.
  26. */
  27. form: function () {
  28. let form = { actor: this.actorID };
  29. // What is this environment's type?
  30. if (this.obj.type == "declarative") {
  31. form.type = this.obj.callee ? "function" : "block";
  32. } else {
  33. form.type = this.obj.type;
  34. }
  35. // Does this environment have a parent?
  36. if (this.obj.parent) {
  37. form.parent = (this.threadActor
  38. .createEnvironmentActor(this.obj.parent,
  39. this.registeredPool)
  40. .form());
  41. }
  42. // Does this environment reflect the properties of an object as variables?
  43. if (this.obj.type == "object" || this.obj.type == "with") {
  44. form.object = createValueGrip(this.obj.object,
  45. this.registeredPool, this.threadActor.objectGrip);
  46. }
  47. // Is this the environment created for a function call?
  48. if (this.obj.callee) {
  49. form.function = createValueGrip(this.obj.callee,
  50. this.registeredPool, this.threadActor.objectGrip);
  51. }
  52. // Shall we list this environment's bindings?
  53. if (this.obj.type == "declarative") {
  54. form.bindings = this.bindings();
  55. }
  56. return form;
  57. },
  58. /**
  59. * Handle a protocol request to change the value of a variable bound in this
  60. * lexical environment.
  61. *
  62. * @param string name
  63. * The name of the variable to be changed.
  64. * @param any value
  65. * The value to be assigned.
  66. */
  67. assign: function (name, value) {
  68. // TODO: enable the commented-out part when getVariableDescriptor lands
  69. // (bug 725815).
  70. /* let desc = this.obj.getVariableDescriptor(name);
  71. if (!desc.writable) {
  72. return { error: "immutableBinding",
  73. message: "Changing the value of an immutable binding is not " +
  74. "allowed" };
  75. }*/
  76. try {
  77. this.obj.setVariable(name, value);
  78. } catch (e) {
  79. if (e instanceof Debugger.DebuggeeWouldRun) {
  80. throw {
  81. error: "threadWouldRun",
  82. message: "Assigning a value would cause the debuggee to run"
  83. };
  84. } else {
  85. throw e;
  86. }
  87. }
  88. return { from: this.actorID };
  89. },
  90. /**
  91. * Handle a protocol request to fully enumerate the bindings introduced by the
  92. * lexical environment.
  93. */
  94. bindings: function () {
  95. let bindings = { arguments: [], variables: {} };
  96. // TODO: this part should be removed in favor of the commented-out part
  97. // below when getVariableDescriptor lands (bug 725815).
  98. if (typeof this.obj.getVariable != "function") {
  99. // if (typeof this.obj.getVariableDescriptor != "function") {
  100. return bindings;
  101. }
  102. let parameterNames;
  103. if (this.obj.callee) {
  104. parameterNames = this.obj.callee.parameterNames;
  105. } else {
  106. parameterNames = [];
  107. }
  108. for (let name of parameterNames) {
  109. let arg = {};
  110. let value = this.obj.getVariable(name);
  111. // TODO: this part should be removed in favor of the commented-out part
  112. // below when getVariableDescriptor lands (bug 725815).
  113. let desc = {
  114. value: value,
  115. configurable: false,
  116. writable: !(value && value.optimizedOut),
  117. enumerable: true
  118. };
  119. // let desc = this.obj.getVariableDescriptor(name);
  120. let descForm = {
  121. enumerable: true,
  122. configurable: desc.configurable
  123. };
  124. if ("value" in desc) {
  125. descForm.value = createValueGrip(desc.value,
  126. this.registeredPool, this.threadActor.objectGrip);
  127. descForm.writable = desc.writable;
  128. } else {
  129. descForm.get = createValueGrip(desc.get, this.registeredPool,
  130. this.threadActor.objectGrip);
  131. descForm.set = createValueGrip(desc.set, this.registeredPool,
  132. this.threadActor.objectGrip);
  133. }
  134. arg[name] = descForm;
  135. bindings.arguments.push(arg);
  136. }
  137. for (let name of this.obj.names()) {
  138. if (bindings.arguments.some(function exists(element) {
  139. return !!element[name];
  140. })) {
  141. continue;
  142. }
  143. let value = this.obj.getVariable(name);
  144. // TODO: this part should be removed in favor of the commented-out part
  145. // below when getVariableDescriptor lands.
  146. let desc = {
  147. value: value,
  148. configurable: false,
  149. writable: !(value &&
  150. (value.optimizedOut ||
  151. value.uninitialized ||
  152. value.missingArguments)),
  153. enumerable: true
  154. };
  155. // let desc = this.obj.getVariableDescriptor(name);
  156. let descForm = {
  157. enumerable: true,
  158. configurable: desc.configurable
  159. };
  160. if ("value" in desc) {
  161. descForm.value = createValueGrip(desc.value,
  162. this.registeredPool, this.threadActor.objectGrip);
  163. descForm.writable = desc.writable;
  164. } else {
  165. descForm.get = createValueGrip(desc.get || undefined,
  166. this.registeredPool, this.threadActor.objectGrip);
  167. descForm.set = createValueGrip(desc.set || undefined,
  168. this.registeredPool, this.threadActor.objectGrip);
  169. }
  170. bindings.variables[name] = descForm;
  171. }
  172. return bindings;
  173. }
  174. });
  175. exports.EnvironmentActor = EnvironmentActor;