1
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
3
* The contents of this file are subject to the Netscape Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/NPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is Rhino code, released
16
* The Initial Developer of the Original Code is Netscape
17
* Communications Corporation. Portions created by Netscape are
18
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
25
* Alternatively, the contents of this file may be used under the
26
* terms of the GNU Public License (the "GPL"), in which case the
27
* provisions of the GPL are applicable instead of those above.
28
* If you wish to allow use of your version of this file only
29
* under the terms of the GPL and not to allow others to use your
30
* version of this file under the NPL, indicate your decision by
31
* deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL. If you do not delete
33
* the provisions above, a recipient may use your version of this
34
* file under either the NPL or the GPL.
37
package org.mozilla.javascript;
40
* This class implements the Math native object.
45
public class NativeMath extends IdScriptable
47
public static void init(Context cx, Scriptable scope, boolean sealed) {
48
NativeMath obj = new NativeMath();
49
obj.setSealFunctionsFlag(sealed);
50
obj.setFunctionParametrs(cx);
51
obj.setPrototype(getObjectPrototype(scope));
52
obj.setParentScope(scope);
53
if (sealed) { obj.sealObject(); }
54
ScriptableObject.defineProperty(scope, "Math", obj,
55
ScriptableObject.DONTENUM);
58
public String getClassName() { return "Math"; }
60
protected int getIdDefaultAttributes(int id) {
61
if (id > LAST_METHOD_ID) {
62
return DONTENUM | READONLY | PERMANENT;
64
return super.getIdDefaultAttributes(id);
67
protected Object getIdValue(int id) {
68
if (id > LAST_METHOD_ID) {
69
return cacheIdValue(id, wrap_double(getField(id)));
71
return super.getIdValue(id);
74
private double getField(int fieldId) {
77
case Id_PI: return PI;
78
case Id_LN10: return LN10;
79
case Id_LN2: return LN2;
80
case Id_LOG2E: return LOG2E;
81
case Id_LOG10E: return LOG10E;
82
case Id_SQRT1_2: return SQRT1_2;
83
case Id_SQRT2: return SQRT2;
85
return 0; // Unreachable
88
public int methodArity(int methodId) {
90
case Id_abs: return 1;
91
case Id_acos: return 1;
92
case Id_asin: return 1;
93
case Id_atan: return 1;
94
case Id_atan2: return 2;
95
case Id_ceil: return 1;
96
case Id_cos: return 1;
97
case Id_exp: return 1;
98
case Id_floor: return 1;
99
case Id_log: return 1;
100
case Id_max: return 2;
101
case Id_min: return 2;
102
case Id_pow: return 2;
103
case Id_random: return 0;
104
case Id_round: return 1;
105
case Id_sin: return 1;
106
case Id_sqrt: return 1;
107
case Id_tan: return 1;
109
return super.methodArity(methodId);
112
public Object execMethod
113
(int methodId, IdFunction f,
114
Context cx, Scriptable scope, Scriptable thisObj, Object[] args)
115
throws JavaScriptException
118
case Id_abs: return wrap_double
119
(js_abs(ScriptRuntime.toNumber(args, 0)));
121
case Id_acos: return wrap_double
122
(js_acos(ScriptRuntime.toNumber(args, 0)));
124
case Id_asin: return wrap_double
125
(js_asin(ScriptRuntime.toNumber(args, 0)));
127
case Id_atan: return wrap_double
128
(js_atan(ScriptRuntime.toNumber(args, 0)));
130
case Id_atan2: return wrap_double
131
(js_atan2(ScriptRuntime.toNumber(args, 0),
132
ScriptRuntime.toNumber(args, 1)));
134
case Id_ceil: return wrap_double
135
(js_ceil(ScriptRuntime.toNumber(args, 0)));
137
case Id_cos: return wrap_double
138
(js_cos(ScriptRuntime.toNumber(args, 0)));
140
case Id_exp: return wrap_double
141
(js_exp(ScriptRuntime.toNumber(args, 0)));
143
case Id_floor: return wrap_double
144
(js_floor(ScriptRuntime.toNumber(args, 0)));
146
case Id_log: return wrap_double
147
(js_log(ScriptRuntime.toNumber(args, 0)));
149
case Id_max: return wrap_double
152
case Id_min: return wrap_double
155
case Id_pow: return wrap_double
156
(js_pow(ScriptRuntime.toNumber(args, 0),
157
ScriptRuntime.toNumber(args, 1)));
159
case Id_random: return wrap_double
162
case Id_round: return wrap_double
163
(js_round(ScriptRuntime.toNumber(args, 0)));
165
case Id_sin: return wrap_double
166
(js_sin(ScriptRuntime.toNumber(args, 0)));
168
case Id_sqrt: return wrap_double
169
(js_sqrt(ScriptRuntime.toNumber(args, 0)));
171
case Id_tan: return wrap_double
172
(js_tan(ScriptRuntime.toNumber(args, 0)));
174
return super.execMethod(methodId, f, cx, scope, thisObj, args);
177
private double js_abs(double x) {
178
// abs(-0.0) should be 0.0, but -0.0 < 0.0 == false
179
return (x == 0.0) ? 0.0 : (x < 0.0) ? -x : x;
182
private double js_acos(double x) {
183
return (x == x && -1.0 <= x && x <= 1.0) ? Math.acos(x) : Double.NaN;
186
private double js_asin(double x) {
187
return (x == x && -1.0 <= x && x <= 1.0) ? Math.asin(x) : Double.NaN;
190
private double js_atan(double x) { return Math.atan(x); }
192
private double js_atan2(double x, double y) { return Math.atan2(x, y); }
194
private double js_ceil(double x) { return Math.ceil(x); }
196
private double js_cos(double x) { return Math.cos(x); }
198
private double js_exp(double x) {
199
return (x == Double.POSITIVE_INFINITY) ? x
200
: (x == Double.NEGATIVE_INFINITY) ? 0.0
204
private double js_floor(double x) { return Math.floor(x); }
206
private double js_log(double x) {
207
// Java's log(<0) = -Infinity; we need NaN
208
return (x < 0) ? Double.NaN : Math.log(x);
211
private double js_max(Object[] args) {
212
double result = Double.NEGATIVE_INFINITY;
213
if (args.length == 0)
215
for (int i = 0; i < args.length; i++) {
216
double d = ScriptRuntime.toNumber(args[i]);
217
if (d != d) return d;
218
// if (result < d) result = d; does not work due to -0.0 >= +0.0
219
result = Math.max(result, d);
224
private double js_min(Object[] args) {
225
double result = Double.POSITIVE_INFINITY;
226
if (args.length == 0)
228
for (int i = 0; i < args.length; i++) {
229
double d = ScriptRuntime.toNumber(args[i]);
230
if (d != d) return d;
231
// if (result > d) result = d; does not work due to -0.0 >= +0.0
232
result = Math.min(result, d);
237
private double js_pow(double x, double y) {
238
if (y == 0) return 1.0; // Java's pow(NaN, 0) = NaN; we need 1
239
if ((x == 0) && (y < 0)) {
241
// x is +0, Java is -oo, we need +oo
242
return Double.POSITIVE_INFINITY;
244
/* if x is -0 and y is an odd integer, -oo */
246
if (y_int == y && (y_int & 0x1) != 0)
247
return Double.NEGATIVE_INFINITY;
248
return Double.POSITIVE_INFINITY;
250
return Math.pow(x, y);
253
private double js_random() { return Math.random(); }
255
private double js_round(double d) {
258
if (d == Double.POSITIVE_INFINITY || d == Double.NEGATIVE_INFINITY)
260
long l = Math.round(d);
262
// We must propagate the sign of d into the result
264
return ScriptRuntime.negativeZero;
265
return d == 0.0 ? d : 0.0;
270
private double js_sin(double x) { return Math.sin(x); }
272
private double js_sqrt(double x) { return Math.sqrt(x); }
274
private double js_tan(double x) { return Math.tan(x); }
276
protected int maxInstanceId() { return MAX_INSTANCE_ID; }
278
protected String getIdName(int id) {
280
case Id_abs: return "abs";
281
case Id_acos: return "acos";
282
case Id_asin: return "asin";
283
case Id_atan: return "atan";
284
case Id_atan2: return "atan2";
285
case Id_ceil: return "ceil";
286
case Id_cos: return "cos";
287
case Id_exp: return "exp";
288
case Id_floor: return "floor";
289
case Id_log: return "log";
290
case Id_max: return "max";
291
case Id_min: return "min";
292
case Id_pow: return "pow";
293
case Id_random: return "random";
294
case Id_round: return "round";
295
case Id_sin: return "sin";
296
case Id_sqrt: return "sqrt";
297
case Id_tan: return "tan";
299
case Id_E: return "E";
300
case Id_PI: return "PI";
301
case Id_LN10: return "LN10";
302
case Id_LN2: return "LN2";
303
case Id_LOG2E: return "LOG2E";
304
case Id_LOG10E: return "LOG10E";
305
case Id_SQRT1_2: return "SQRT1_2";
306
case Id_SQRT2: return "SQRT2";
313
protected int mapNameToId(String s) {
315
// #generated# Last update: 2001-03-23 13:50:14 GMT+01:00
316
L0: { id = 0; String X = null; int c;
317
L: switch (s.length()) {
318
case 1: if (s.charAt(0)=='E') {id=Id_E; break L0;} break L;
319
case 2: if (s.charAt(0)=='P' && s.charAt(1)=='I') {id=Id_PI; break L0;} break L;
320
case 3: switch (s.charAt(0)) {
321
case 'L': if (s.charAt(2)=='2' && s.charAt(1)=='N') {id=Id_LN2; break L0;} break L;
322
case 'a': if (s.charAt(2)=='s' && s.charAt(1)=='b') {id=Id_abs; break L0;} break L;
323
case 'c': if (s.charAt(2)=='s' && s.charAt(1)=='o') {id=Id_cos; break L0;} break L;
324
case 'e': if (s.charAt(2)=='p' && s.charAt(1)=='x') {id=Id_exp; break L0;} break L;
325
case 'l': if (s.charAt(2)=='g' && s.charAt(1)=='o') {id=Id_log; break L0;} break L;
326
case 'm': c=s.charAt(2);
327
if (c=='n') { if (s.charAt(1)=='i') {id=Id_min; break L0;} }
328
else if (c=='x') { if (s.charAt(1)=='a') {id=Id_max; break L0;} }
330
case 'p': if (s.charAt(2)=='w' && s.charAt(1)=='o') {id=Id_pow; break L0;} break L;
331
case 's': if (s.charAt(2)=='n' && s.charAt(1)=='i') {id=Id_sin; break L0;} break L;
332
case 't': if (s.charAt(2)=='n' && s.charAt(1)=='a') {id=Id_tan; break L0;} break L;
334
case 4: switch (s.charAt(1)) {
335
case 'N': X="LN10";id=Id_LN10; break L;
336
case 'c': X="acos";id=Id_acos; break L;
337
case 'e': X="ceil";id=Id_ceil; break L;
338
case 'q': X="sqrt";id=Id_sqrt; break L;
339
case 's': X="asin";id=Id_asin; break L;
340
case 't': X="atan";id=Id_atan; break L;
342
case 5: switch (s.charAt(0)) {
343
case 'L': X="LOG2E";id=Id_LOG2E; break L;
344
case 'S': X="SQRT2";id=Id_SQRT2; break L;
345
case 'a': X="atan2";id=Id_atan2; break L;
346
case 'f': X="floor";id=Id_floor; break L;
347
case 'r': X="round";id=Id_round; break L;
349
case 6: c=s.charAt(0);
350
if (c=='L') { X="LOG10E";id=Id_LOG10E; }
351
else if (c=='r') { X="random";id=Id_random; }
353
case 7: X="SQRT1_2";id=Id_SQRT1_2; break L;
355
if (X!=null && X!=s && !X.equals(s)) id = 0;
361
private static final int
392
MAX_INSTANCE_ID = 26;
396
private static final double
399
LN10 = 2.302585092994046,
400
LN2 = 0.6931471805599453,
401
LOG2E = 1.4426950408889634,
402
LOG10E = 0.4342944819032518,
403
SQRT1_2 = 0.7071067811865476,
404
SQRT2 = 1.4142135623730951;
1
/* -*- Mode: java; tab-width: 4; indent-tabs-mode: 1; c-basic-offset: 4 -*-
3
* The contents of this file are subject to the Netscape Public
4
* License Version 1.1 (the "License"); you may not use this file
5
* except in compliance with the License. You may obtain a copy of
6
* the License at http://www.mozilla.org/NPL/
8
* Software distributed under the License is distributed on an "AS
9
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
10
* implied. See the License for the specific language governing
11
* rights and limitations under the License.
13
* The Original Code is Rhino code, released
16
* The Initial Developer of the Original Code is Netscape
17
* Communications Corporation. Portions created by Netscape are
18
* Copyright (C) 1997-1999 Netscape Communications Corporation. All
25
* Alternatively, the contents of this file may be used under the
26
* terms of the GNU Public License (the "GPL"), in which case the
27
* provisions of the GPL are applicable instead of those above.
28
* If you wish to allow use of your version of this file only
29
* under the terms of the GPL and not to allow others to use your
30
* version of this file under the NPL, indicate your decision by
31
* deleting the provisions above and replace them with the notice
32
* and other provisions required by the GPL. If you do not delete
33
* the provisions above, a recipient may use your version of this
34
* file under either the NPL or the GPL.
37
package org.mozilla.javascript;
40
* This class implements the Math native object.
45
final class NativeMath extends IdScriptableObject
47
private static final Object MATH_TAG = new Object();
49
static void init(Context cx, Scriptable scope, boolean sealed)
51
NativeMath obj = new NativeMath();
52
obj.activatePrototypeMap(MAX_ID);
53
obj.setPrototype(getObjectPrototype(scope));
54
obj.setParentScope(scope);
55
if (sealed) { obj.sealObject(); }
56
ScriptableObject.defineProperty(scope, "Math", obj,
57
ScriptableObject.DONTENUM);
64
public String getClassName() { return "Math"; }
66
protected void initPrototypeId(int id)
68
if (id <= LAST_METHOD_ID) {
72
case Id_toSource: arity = 0; name = "toSource"; break;
73
case Id_abs: arity = 1; name = "abs"; break;
74
case Id_acos: arity = 1; name = "acos"; break;
75
case Id_asin: arity = 1; name = "asin"; break;
76
case Id_atan: arity = 1; name = "atan"; break;
77
case Id_atan2: arity = 2; name = "atan2"; break;
78
case Id_ceil: arity = 1; name = "ceil"; break;
79
case Id_cos: arity = 1; name = "cos"; break;
80
case Id_exp: arity = 1; name = "exp"; break;
81
case Id_floor: arity = 1; name = "floor"; break;
82
case Id_log: arity = 1; name = "log"; break;
83
case Id_max: arity = 2; name = "max"; break;
84
case Id_min: arity = 2; name = "min"; break;
85
case Id_pow: arity = 2; name = "pow"; break;
86
case Id_random: arity = 0; name = "random"; break;
87
case Id_round: arity = 1; name = "round"; break;
88
case Id_sin: arity = 1; name = "sin"; break;
89
case Id_sqrt: arity = 1; name = "sqrt"; break;
90
case Id_tan: arity = 1; name = "tan"; break;
91
default: throw new IllegalStateException(String.valueOf(id));
93
initPrototypeMethod(MATH_TAG, id, name, arity);
98
case Id_E: x = Math.E; name = "E"; break;
99
case Id_PI: x = Math.PI; name = "PI"; break;
100
case Id_LN10: x = 2.302585092994046; name = "LN10"; break;
101
case Id_LN2: x = 0.6931471805599453; name = "LN2"; break;
102
case Id_LOG2E: x = 1.4426950408889634; name = "LOG2E"; break;
103
case Id_LOG10E: x = 0.4342944819032518; name = "LOG10E"; break;
104
case Id_SQRT1_2: x = 0.7071067811865476; name = "SQRT1_2"; break;
105
case Id_SQRT2: x = 1.4142135623730951; name = "SQRT2"; break;
106
default: throw new IllegalStateException(String.valueOf(id));
108
initPrototypeValue(id, name, ScriptRuntime.wrapNumber(x),
109
DONTENUM | READONLY | PERMANENT);
113
public Object execIdCall(IdFunctionObject f, Context cx, Scriptable scope,
114
Scriptable thisObj, Object[] args)
116
if (!f.hasTag(MATH_TAG)) {
117
return super.execIdCall(f, cx, scope, thisObj, args);
120
int methodId = f.methodId();
126
x = ScriptRuntime.toNumber(args, 0);
127
// abs(-0.0) should be 0.0, but -0.0 < 0.0 == false
128
x = (x == 0.0) ? 0.0 : (x < 0.0) ? -x : x;
133
x = ScriptRuntime.toNumber(args, 0);
134
if (x == x && -1.0 <= x && x <= 1.0) {
135
x = (methodId == Id_acos) ? Math.acos(x) : Math.asin(x);
142
x = ScriptRuntime.toNumber(args, 0);
147
x = ScriptRuntime.toNumber(args, 0);
148
x = Math.atan2(x, ScriptRuntime.toNumber(args, 1));
152
x = ScriptRuntime.toNumber(args, 0);
157
x = ScriptRuntime.toNumber(args, 0);
158
x = (x == Double.POSITIVE_INFINITY
159
|| x == Double.NEGATIVE_INFINITY)
160
? Double.NaN : Math.cos(x);
164
x = ScriptRuntime.toNumber(args, 0);
165
x = (x == Double.POSITIVE_INFINITY) ? x
166
: (x == Double.NEGATIVE_INFINITY) ? 0.0
171
x = ScriptRuntime.toNumber(args, 0);
176
x = ScriptRuntime.toNumber(args, 0);
177
// Java's log(<0) = -Infinity; we need NaN
178
x = (x < 0) ? Double.NaN : Math.log(x);
183
x = (methodId == Id_max)
184
? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;
185
for (int i = 0; i != args.length; ++i) {
186
double d = ScriptRuntime.toNumber(args[i]);
191
if (methodId == Id_max) {
192
// if (x < d) x = d; does not work due to -0.0 >= +0.0
201
x = ScriptRuntime.toNumber(args, 0);
202
x = js_pow(x, ScriptRuntime.toNumber(args, 1));
210
x = ScriptRuntime.toNumber(args, 0);
211
if (x == x && x != Double.POSITIVE_INFINITY
212
&& x != Double.NEGATIVE_INFINITY)
214
// Round only finite x
215
long l = Math.round(x);
219
// We must propagate the sign of d into the result
221
x = ScriptRuntime.negativeZero;
222
} else if (x != 0.0) {
230
x = ScriptRuntime.toNumber(args, 0);
231
x = (x == Double.POSITIVE_INFINITY
232
|| x == Double.NEGATIVE_INFINITY)
233
? Double.NaN : Math.sin(x);
237
x = ScriptRuntime.toNumber(args, 0);
242
x = ScriptRuntime.toNumber(args, 0);
246
default: throw new IllegalStateException(String.valueOf(methodId));
248
return ScriptRuntime.wrapNumber(x);
251
// See Ecma 15.8.2.13
252
private double js_pow(double x, double y) {
255
// y is NaN, result is always NaN
258
// Java's pow(NaN, 0) = NaN; we need 1
261
// Many dirrerences from Java's Math.pow
263
result = (y > 0) ? 0 : Double.POSITIVE_INFINITY;
265
// x is -0, need to check if y is an odd integer
266
long y_long = (long)y;
267
if (y_long == y && (y_long & 0x1) != 0) {
268
result = (y > 0) ? -0.0 : Double.NEGATIVE_INFINITY;
270
result = (y > 0) ? 0.0 : Double.POSITIVE_INFINITY;
274
result = Math.pow(x, y);
275
if (result != result) {
276
// Check for broken Java implementations that gives NaN
277
// when they should return something else
278
if (y == Double.POSITIVE_INFINITY) {
279
if (x < -1.0 || 1.0 < x) {
280
result = Double.POSITIVE_INFINITY;
281
} else if (-1.0 < x && x < 1.0) {
284
} else if (y == Double.NEGATIVE_INFINITY) {
285
if (x < -1.0 || 1.0 < x) {
287
} else if (-1.0 < x && x < 1.0) {
288
result = Double.POSITIVE_INFINITY;
290
} else if (x == Double.POSITIVE_INFINITY) {
291
result = (y > 0) ? Double.POSITIVE_INFINITY : 0.0;
292
} else if (x == Double.NEGATIVE_INFINITY) {
293
long y_long = (long)y;
294
if (y_long == y && (y_long & 0x1) != 0) {
296
result = (y > 0) ? Double.NEGATIVE_INFINITY : -0.0;
298
result = (y > 0) ? Double.POSITIVE_INFINITY : 0.0;
308
protected int findPrototypeId(String s)
311
// #generated# Last update: 2004-03-17 13:51:32 CET
312
L0: { id = 0; String X = null; int c;
313
L: switch (s.length()) {
314
case 1: if (s.charAt(0)=='E') {id=Id_E; break L0;} break L;
315
case 2: if (s.charAt(0)=='P' && s.charAt(1)=='I') {id=Id_PI; break L0;} break L;
316
case 3: switch (s.charAt(0)) {
317
case 'L': if (s.charAt(2)=='2' && s.charAt(1)=='N') {id=Id_LN2; break L0;} break L;
318
case 'a': if (s.charAt(2)=='s' && s.charAt(1)=='b') {id=Id_abs; break L0;} break L;
319
case 'c': if (s.charAt(2)=='s' && s.charAt(1)=='o') {id=Id_cos; break L0;} break L;
320
case 'e': if (s.charAt(2)=='p' && s.charAt(1)=='x') {id=Id_exp; break L0;} break L;
321
case 'l': if (s.charAt(2)=='g' && s.charAt(1)=='o') {id=Id_log; break L0;} break L;
322
case 'm': c=s.charAt(2);
323
if (c=='n') { if (s.charAt(1)=='i') {id=Id_min; break L0;} }
324
else if (c=='x') { if (s.charAt(1)=='a') {id=Id_max; break L0;} }
326
case 'p': if (s.charAt(2)=='w' && s.charAt(1)=='o') {id=Id_pow; break L0;} break L;
327
case 's': if (s.charAt(2)=='n' && s.charAt(1)=='i') {id=Id_sin; break L0;} break L;
328
case 't': if (s.charAt(2)=='n' && s.charAt(1)=='a') {id=Id_tan; break L0;} break L;
330
case 4: switch (s.charAt(1)) {
331
case 'N': X="LN10";id=Id_LN10; break L;
332
case 'c': X="acos";id=Id_acos; break L;
333
case 'e': X="ceil";id=Id_ceil; break L;
334
case 'q': X="sqrt";id=Id_sqrt; break L;
335
case 's': X="asin";id=Id_asin; break L;
336
case 't': X="atan";id=Id_atan; break L;
338
case 5: switch (s.charAt(0)) {
339
case 'L': X="LOG2E";id=Id_LOG2E; break L;
340
case 'S': X="SQRT2";id=Id_SQRT2; break L;
341
case 'a': X="atan2";id=Id_atan2; break L;
342
case 'f': X="floor";id=Id_floor; break L;
343
case 'r': X="round";id=Id_round; break L;
345
case 6: c=s.charAt(0);
346
if (c=='L') { X="LOG10E";id=Id_LOG10E; }
347
else if (c=='r') { X="random";id=Id_random; }
349
case 7: X="SQRT1_2";id=Id_SQRT1_2; break L;
350
case 8: X="toSource";id=Id_toSource; break L;
352
if (X!=null && X!=s && !X.equals(s)) id = 0;
358
private static final int
381
private static final int
382
Id_E = LAST_METHOD_ID + 1,
383
Id_PI = LAST_METHOD_ID + 2,
384
Id_LN10 = LAST_METHOD_ID + 3,
385
Id_LN2 = LAST_METHOD_ID + 4,
386
Id_LOG2E = LAST_METHOD_ID + 5,
387
Id_LOG10E = LAST_METHOD_ID + 6,
388
Id_SQRT1_2 = LAST_METHOD_ID + 7,
389
Id_SQRT2 = LAST_METHOD_ID + 8,
391
MAX_ID = LAST_METHOD_ID + 8;