blob: dcd2b01822983236dc003155bc9e16799f781dc9 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
35#include "compiler.h"
36#include "cpu.h"
37#include "dateparser.h"
38#include "debug.h"
39#include "execution.h"
40#include "jsregexp.h"
41#include "platform.h"
42#include "runtime.h"
43#include "scopeinfo.h"
44#include "v8threads.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000045#include "smart-pointer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
47namespace v8 { namespace internal {
48
49
50#define RUNTIME_ASSERT(value) do { \
51 if (!(value)) return IllegalOperation(); \
52} while (false)
53
54// Cast the given object to a value of the specified type and store
55// it in a variable with the given name. If the object is not of the
56// expected type call IllegalOperation and return.
57#define CONVERT_CHECKED(Type, name, obj) \
58 RUNTIME_ASSERT(obj->Is##Type()); \
59 Type* name = Type::cast(obj);
60
61#define CONVERT_ARG_CHECKED(Type, name, index) \
62 RUNTIME_ASSERT(args[index]->Is##Type()); \
63 Handle<Type> name = args.at<Type>(index);
64
kasper.lundbd3ec4e2008-07-09 11:06:54 +000065// Cast the given object to a boolean and store it in a variable with
66// the given name. If the object is not a boolean call IllegalOperation
67// and return.
68#define CONVERT_BOOLEAN_CHECKED(name, obj) \
69 RUNTIME_ASSERT(obj->IsBoolean()); \
70 bool name = (obj)->IsTrue();
71
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000072// Cast the given object to a double and store it in a variable with
73// the given name. If the object is not a number (as opposed to
74// the number not-a-number) call IllegalOperation and return.
75#define CONVERT_DOUBLE_CHECKED(name, obj) \
76 RUNTIME_ASSERT(obj->IsNumber()); \
77 double name = (obj)->Number();
78
79// Call the specified converter on the object *comand store the result in
80// a variable of the specified type with the given name. If the
81// object is not a Number call IllegalOperation and return.
82#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
83 RUNTIME_ASSERT(obj->IsNumber()); \
84 type name = NumberTo##Type(obj);
85
86// Non-reentrant string buffer for efficient general use in this file.
87static StaticResource<StringInputBuffer> string_input_buffer;
88
89
90static Object* IllegalOperation() {
91 return Top::Throw(Heap::illegal_access_symbol());
92}
93
94
95static Object* Runtime_CloneObjectLiteralBoilerplate(Arguments args) {
96 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000097 return Heap::CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098}
99
100
ager@chromium.org236ad962008-09-25 09:45:57 +0000101static Handle<Map> ComputeObjectLiteralMap(
102 Handle<Context> context,
103 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000104 bool* is_result_from_cache) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000105 if (FLAG_canonicalize_object_literal_maps) {
106 // First find prefix of consecutive symbol keys.
107 int number_of_properties = constant_properties->length()/2;
108 int number_of_symbol_keys = 0;
109 while ((number_of_symbol_keys < number_of_properties) &&
110 (constant_properties->get(number_of_symbol_keys*2)->IsSymbol())) {
111 number_of_symbol_keys++;
112 }
113 // Based on the number of prefix symbols key we decide whether
114 // to use the map cache in the global context.
115 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000116 if ((number_of_symbol_keys == number_of_properties) &&
117 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000118 // Create the fixed array with the key.
119 Handle<FixedArray> keys = Factory::NewFixedArray(number_of_symbol_keys);
120 for (int i = 0; i < number_of_symbol_keys; i++) {
121 keys->set(i, constant_properties->get(i*2));
122 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000123 *is_result_from_cache = true;
ager@chromium.org236ad962008-09-25 09:45:57 +0000124 return Factory::ObjectLiteralMapFromCache(context, keys);
125 }
126 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000127 *is_result_from_cache = false;
ager@chromium.org236ad962008-09-25 09:45:57 +0000128 return Handle<Map>(context->object_function()->initial_map());
129}
130
131
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000132static Object* Runtime_CreateObjectLiteralBoilerplate(Arguments args) {
133 HandleScope scope;
134 ASSERT(args.length() == 3);
135 // Copy the arguments.
136 Handle<FixedArray> literals = args.at<FixedArray>(0);
137 int literals_index = Smi::cast(args[1])->value();
138 Handle<FixedArray> constant_properties = args.at<FixedArray>(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000139
140 // Get the global context from the literals array. This is the
141 // context in which the function was created and we use the object
142 // function from this context to create the object literal. We do
143 // not use the object function from the current global context
144 // because this might be the object function from another context
145 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000146 Handle<Context> context =
147 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
148
149 bool is_result_from_cache;
150 Handle<Map> map = ComputeObjectLiteralMap(context,
151 constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000152 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000153
ager@chromium.org236ad962008-09-25 09:45:57 +0000154 Handle<JSObject> boilerplate = Factory::NewJSObjectFromMap(map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 { // Add the constant propeties to the boilerplate.
156 int length = constant_properties->length();
ager@chromium.org236ad962008-09-25 09:45:57 +0000157 OptimizedObjectForAddingMultipleProperties opt(boilerplate,
158 !is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000159 for (int index = 0; index < length; index +=2) {
160 Handle<Object> key(constant_properties->get(index+0));
161 Handle<Object> value(constant_properties->get(index+1));
162 uint32_t element_index = 0;
163 if (key->IsSymbol()) {
164 // If key is a symbol it is not an array element.
165 Handle<String> name(String::cast(*key));
166 ASSERT(!name->AsArrayIndex(&element_index));
167 SetProperty(boilerplate, name, value, NONE);
168 } else if (Array::IndexFromObject(*key, &element_index)) {
169 // Array index (uint32).
170 SetElement(boilerplate, element_index, value);
171 } else {
172 // Non-uint32 number.
173 ASSERT(key->IsNumber());
174 double num = key->Number();
175 char arr[100];
176 Vector<char> buffer(arr, ARRAY_SIZE(arr));
177 const char* str = DoubleToCString(num, buffer);
178 Handle<String> name = Factory::NewStringFromAscii(CStrVector(str));
179 SetProperty(boilerplate, name, value, NONE);
180 }
181 }
182 }
183
184 // Update the functions literal and return the boilerplate.
185 literals->set(literals_index, *boilerplate);
186
187 return *boilerplate;
188}
189
190
191static Object* Runtime_CreateArrayLiteral(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192 // Takes a FixedArray of elements containing the literal elements of
193 // the array literal and produces JSArray with those elements.
194 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000195 // which contains the context from which to get the Array function
196 // to use for creating the array literal.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000197 ASSERT(args.length() == 2);
198 CONVERT_CHECKED(FixedArray, elements, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000199 CONVERT_CHECKED(FixedArray, literals, args[1]);
ager@chromium.org236ad962008-09-25 09:45:57 +0000200 JSFunction* constructor =
201 JSFunction::GlobalContextFromLiterals(literals)->array_function();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000202 // Create the JSArray.
203 Object* object = Heap::AllocateJSObject(constructor);
204 if (object->IsFailure()) return object;
205
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206 // Copy the elements.
207 Object* content = elements->Copy();
208 if (content->IsFailure()) return content;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000209
210 // Set the elements.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000211 JSArray::cast(object)->SetContent(FixedArray::cast(content));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000212 return object;
213}
214
215
216static Object* Runtime_ClassOf(Arguments args) {
217 NoHandleAllocation ha;
218 ASSERT(args.length() == 1);
219 Object* obj = args[0];
220 if (!obj->IsJSObject()) return Heap::null_value();
221 return JSObject::cast(obj)->class_name();
222}
223
ager@chromium.org7c537e22008-10-16 08:43:32 +0000224
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000225static Object* Runtime_HasStringClass(Arguments args) {
226 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::String_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000227}
228
229
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000230static Object* Runtime_HasDateClass(Arguments args) {
231 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Date_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000232}
233
234
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000235static Object* Runtime_HasArrayClass(Arguments args) {
236 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Array_symbol()));
237}
238
239
240static Object* Runtime_HasFunctionClass(Arguments args) {
241 return Heap::ToBoolean(
242 args[0]->HasSpecificClassOf(Heap::function_class_symbol()));
243}
244
245
246static Object* Runtime_HasNumberClass(Arguments args) {
247 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Number_symbol()));
248}
249
250
251static Object* Runtime_HasBooleanClass(Arguments args) {
252 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::Boolean_symbol()));
253}
254
255
256static Object* Runtime_HasArgumentsClass(Arguments args) {
257 return Heap::ToBoolean(
258 args[0]->HasSpecificClassOf(Heap::Arguments_symbol()));
259}
260
261
262static Object* Runtime_HasRegExpClass(Arguments args) {
263 return Heap::ToBoolean(args[0]->HasSpecificClassOf(Heap::RegExp_symbol()));
ager@chromium.org7c537e22008-10-16 08:43:32 +0000264}
265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000266
267static Object* Runtime_IsInPrototypeChain(Arguments args) {
268 NoHandleAllocation ha;
269 ASSERT(args.length() == 2);
270 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
271 Object* O = args[0];
272 Object* V = args[1];
273 while (true) {
274 Object* prototype = V->GetPrototype();
275 if (prototype->IsNull()) return Heap::false_value();
276 if (O == prototype) return Heap::true_value();
277 V = prototype;
278 }
279}
280
281
282static Object* Runtime_IsConstructCall(Arguments args) {
283 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000284 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000285 JavaScriptFrameIterator it;
286 return Heap::ToBoolean(it.frame()->IsConstructor());
287}
288
289
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000290static Object* Runtime_RegExpCompile(Arguments args) {
291 HandleScope scope; // create a new handle scope
292 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 CONVERT_CHECKED(JSRegExp, raw_re, args[0]);
294 Handle<JSRegExp> re(raw_re);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295 CONVERT_CHECKED(String, raw_pattern, args[1]);
296 Handle<String> pattern(raw_pattern);
297 CONVERT_CHECKED(String, raw_flags, args[2]);
298 Handle<String> flags(raw_flags);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000299 return *RegExpImpl::Compile(re, pattern, flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300}
301
302
303static Object* Runtime_CreateApiFunction(Arguments args) {
304 HandleScope scope;
305 ASSERT(args.length() == 1);
306 CONVERT_CHECKED(FunctionTemplateInfo, raw_data, args[0]);
307 Handle<FunctionTemplateInfo> data(raw_data);
308 return *Factory::CreateApiFunction(data);
309}
310
311
312static Object* Runtime_IsTemplate(Arguments args) {
313 ASSERT(args.length() == 1);
314 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000315 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000316 return Heap::ToBoolean(result);
317}
318
319
320static Object* Runtime_GetTemplateField(Arguments args) {
321 ASSERT(args.length() == 2);
322 CONVERT_CHECKED(HeapObject, templ, args[0]);
323 RUNTIME_ASSERT(templ->IsStruct());
324 CONVERT_CHECKED(Smi, field, args[1]);
325 return HeapObject::GetHeapObjectField(templ, field->value());
326}
327
328
329static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
330 HandleScope scope;
331 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
332 Handle<Object> args[2] = { type_handle, name };
333 Handle<Object> error =
334 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
335 return Top::Throw(*error);
336}
337
338
339static Object* Runtime_DeclareGlobals(Arguments args) {
340 HandleScope scope;
341 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
342
343 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
344 Handle<Context> context = args.at<Context>(1);
345 bool is_eval = Smi::cast(args[2])->value() == 1;
346
347 // Compute the property attributes. According to ECMA-262, section
348 // 13, page 71, the property must be read-only and
349 // non-deletable. However, neither SpiderMonkey nor KJS creates the
350 // property as read-only, so we don't either.
351 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
352
353 // Only optimize the object if we intend to add more than 5 properties.
354 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
355
356 // Traverse the name/value pairs and set the properties.
357 int length = pairs->length();
358 for (int i = 0; i < length; i += 2) {
359 HandleScope scope;
360 Handle<String> name(String::cast(pairs->get(i)));
361 Handle<Object> value(pairs->get(i + 1));
362
363 // We have to declare a global const property. To capture we only
364 // assign to it when evaluating the assignment for "const x =
365 // <expr>" the initial value is the hole.
366 bool is_const_property = value->IsTheHole();
367
368 if (value->IsUndefined() || is_const_property) {
369 // Lookup the property in the global object, and don't set the
370 // value of the variable if the property is already there.
371 LookupResult lookup;
372 global->Lookup(*name, &lookup);
373 if (lookup.IsProperty()) {
374 // Determine if the property is local by comparing the holder
375 // against the global object. The information will be used to
376 // avoid throwing re-declaration errors when declaring
377 // variables or constants that exist in the prototype chain.
378 bool is_local = (*global == lookup.holder());
379 // Get the property attributes and determine if the property is
380 // read-only.
381 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
382 bool is_read_only = (attributes & READ_ONLY) != 0;
383 if (lookup.type() == INTERCEPTOR) {
384 // If the interceptor says the property is there, we
385 // just return undefined without overwriting the property.
386 // Otherwise, we continue to setting the property.
387 if (attributes != ABSENT) {
388 // Check if the existing property conflicts with regards to const.
389 if (is_local && (is_read_only || is_const_property)) {
390 const char* type = (is_read_only) ? "const" : "var";
391 return ThrowRedeclarationError(type, name);
392 };
393 // The property already exists without conflicting: Go to
394 // the next declaration.
395 continue;
396 }
397 // Fall-through and introduce the absent property by using
398 // SetProperty.
399 } else {
400 if (is_local && (is_read_only || is_const_property)) {
401 const char* type = (is_read_only) ? "const" : "var";
402 return ThrowRedeclarationError(type, name);
403 }
404 // The property already exists without conflicting: Go to
405 // the next declaration.
406 continue;
407 }
408 }
409 } else {
410 // Copy the function and update its context. Use it as value.
411 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
412 Handle<JSFunction> function =
413 Factory::NewFunctionFromBoilerplate(boilerplate, context);
414 value = function;
415 }
416
417 LookupResult lookup;
418 global->LocalLookup(*name, &lookup);
419
420 PropertyAttributes attributes = is_const_property
421 ? static_cast<PropertyAttributes>(base | READ_ONLY)
422 : base;
423
424 if (lookup.IsProperty()) {
425 // There's a local property that we need to overwrite because
426 // we're either declaring a function or there's an interceptor
427 // that claims the property is absent.
428
429 // Check for conflicting re-declarations. We cannot have
430 // conflicting types in case of intercepted properties because
431 // they are absent.
432 if (lookup.type() != INTERCEPTOR &&
433 (lookup.IsReadOnly() || is_const_property)) {
434 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
435 return ThrowRedeclarationError(type, name);
436 }
437 SetProperty(global, name, value, attributes);
438 } else {
439 // If a property with this name does not already exist on the
440 // global object add the property locally. We take special
441 // precautions to always add it as a local property even in case
442 // of callbacks in the prototype chain (this rules out using
443 // SetProperty). Also, we must use the handle-based version to
444 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000445 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000446 }
447 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000448
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000449 return Heap::undefined_value();
450}
451
452
453static Object* Runtime_DeclareContextSlot(Arguments args) {
454 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000455 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456
ager@chromium.org7c537e22008-10-16 08:43:32 +0000457 CONVERT_ARG_CHECKED(Context, context, 0);
458 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000460 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000462 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000463
464 // Declarations are always done in the function context.
465 context = Handle<Context>(context->fcontext());
466
467 int index;
468 PropertyAttributes attributes;
469 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000470 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471 context->Lookup(name, flags, &index, &attributes);
472
473 if (attributes != ABSENT) {
474 // The name was declared before; check for conflicting
475 // re-declarations: This is similar to the code in parser.cc in
476 // the AstBuildingParser::Declare function.
477 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
478 // Functions are not read-only.
479 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
480 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
481 return ThrowRedeclarationError(type, name);
482 }
483
484 // Initialize it if necessary.
485 if (*initial_value != NULL) {
486 if (index >= 0) {
487 // The variable or constant context slot should always be in
488 // the function context; not in any outer context nor in the
489 // arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000490 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000491 if (((attributes & READ_ONLY) == 0) ||
492 context->get(index)->IsTheHole()) {
493 context->set(index, *initial_value);
494 }
495 } else {
496 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000497 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000498 SetProperty(context_ext, name, initial_value, mode);
499 }
500 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000503 // The property is not in the function context. It needs to be
504 // "declared" in the function context's extension context, or in the
505 // global context.
506 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000507 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000508 // The function context's extension context exists - use it.
509 context_ext = Handle<JSObject>(context->extension());
510 } else {
511 // The function context's extension context does not exists - allocate
512 // it.
513 context_ext = Factory::NewJSObject(Top::context_extension_function());
514 // And store it in the extension slot.
515 context->set_extension(*context_ext);
516 }
517 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000518
ager@chromium.org7c537e22008-10-16 08:43:32 +0000519 // Declare the property by setting it to the initial value if provided,
520 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
521 // constant declarations).
522 ASSERT(!context_ext->HasLocalProperty(*name));
523 Handle<Object> value(Heap::undefined_value());
524 if (*initial_value != NULL) value = initial_value;
525 SetProperty(context_ext, name, value, mode);
526 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
527 }
528
529 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000530}
531
532
533static Object* Runtime_InitializeVarGlobal(Arguments args) {
534 NoHandleAllocation nha;
535
536 // Determine if we need to assign to the variable if it already
537 // exists (based on the number of arguments).
538 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
539 bool assign = args.length() == 2;
540
541 CONVERT_ARG_CHECKED(String, name, 0);
542 GlobalObject* global = Top::context()->global();
543
544 // According to ECMA-262, section 12.2, page 62, the property must
545 // not be deletable.
546 PropertyAttributes attributes = DONT_DELETE;
547
548 // Lookup the property locally in the global object. If it isn't
549 // there, we add the property and take special precautions to always
550 // add it as a local property even in case of callbacks in the
551 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000552 // We have IgnoreAttributesAndSetLocalProperty for this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000553 LookupResult lookup;
554 global->LocalLookup(*name, &lookup);
555 if (!lookup.IsProperty()) {
556 Object* value = (assign) ? args[1] : Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000557 return global->IgnoreAttributesAndSetLocalProperty(*name,
558 value,
559 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000560 }
561
562 // Determine if this is a redeclaration of something read-only.
563 if (lookup.IsReadOnly()) {
564 return ThrowRedeclarationError("const", name);
565 }
566
567 // Determine if this is a redeclaration of an intercepted read-only
568 // property and figure out if the property exists at all.
569 bool found = true;
570 PropertyType type = lookup.type();
571 if (type == INTERCEPTOR) {
572 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
573 if (intercepted == ABSENT) {
574 // The interceptor claims the property isn't there. We need to
575 // make sure to introduce it.
576 found = false;
577 } else if ((intercepted & READ_ONLY) != 0) {
578 // The property is present, but read-only. Since we're trying to
579 // overwrite it with a variable declaration we must throw a
580 // re-declaration error.
581 return ThrowRedeclarationError("const", name);
582 }
583 // Restore global object from context (in case of GC).
584 global = Top::context()->global();
585 }
586
587 if (found && !assign) {
588 // The global property is there and we're not assigning any value
589 // to it. Just return.
590 return Heap::undefined_value();
591 }
592
593 // Assign the value (or undefined) to the property.
594 Object* value = (assign) ? args[1] : Heap::undefined_value();
595 return global->SetProperty(&lookup, *name, value, attributes);
596}
597
598
599static Object* Runtime_InitializeConstGlobal(Arguments args) {
600 // All constants are declared with an initial value. The name
601 // of the constant is the first argument and the initial value
602 // is the second.
603 RUNTIME_ASSERT(args.length() == 2);
604 CONVERT_ARG_CHECKED(String, name, 0);
605 Handle<Object> value = args.at<Object>(1);
606
607 // Get the current global object from top.
608 GlobalObject* global = Top::context()->global();
609
610 // According to ECMA-262, section 12.2, page 62, the property must
611 // not be deletable. Since it's a const, it must be READ_ONLY too.
612 PropertyAttributes attributes =
613 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
614
615 // Lookup the property locally in the global object. If it isn't
616 // there, we add the property and take special precautions to always
617 // add it as a local property even in case of callbacks in the
618 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000619 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000620 LookupResult lookup;
621 global->LocalLookup(*name, &lookup);
622 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000623 return global->IgnoreAttributesAndSetLocalProperty(*name,
624 *value,
625 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 }
627
628 // Determine if this is a redeclaration of something not
629 // read-only. In case the result is hidden behind an interceptor we
630 // need to ask it for the property attributes.
631 if (!lookup.IsReadOnly()) {
632 if (lookup.type() != INTERCEPTOR) {
633 return ThrowRedeclarationError("var", name);
634 }
635
636 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
637
638 // Throw re-declaration error if the intercepted property is present
639 // but not read-only.
640 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
641 return ThrowRedeclarationError("var", name);
642 }
643
644 // Restore global object from context (in case of GC) and continue
645 // with setting the value because the property is either absent or
646 // read-only. We also have to do redo the lookup.
647 global = Top::context()->global();
648
649 // BUG 1213579: Handle the case where we have to set a read-only
650 // property through an interceptor and only do it if it's
651 // uninitialized, e.g. the hole. Nirk...
652 global->SetProperty(*name, *value, attributes);
653 return *value;
654 }
655
656 // Set the value, but only we're assigning the initial value to a
657 // constant. For now, we determine this by checking if the
658 // current value is the hole.
659 PropertyType type = lookup.type();
660 if (type == FIELD) {
661 FixedArray* properties = global->properties();
662 int index = lookup.GetFieldIndex();
663 if (properties->get(index)->IsTheHole()) {
664 properties->set(index, *value);
665 }
666 } else if (type == NORMAL) {
667 Dictionary* dictionary = global->property_dictionary();
668 int entry = lookup.GetDictionaryEntry();
669 if (dictionary->ValueAt(entry)->IsTheHole()) {
670 dictionary->ValueAtPut(entry, *value);
671 }
672 } else {
673 // Ignore re-initialization of constants that have already been
674 // assigned a function value.
675 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
676 }
677
678 // Use the set value as the result of the operation.
679 return *value;
680}
681
682
683static Object* Runtime_InitializeConstContextSlot(Arguments args) {
684 HandleScope scope;
685 ASSERT(args.length() == 3);
686
687 Handle<Object> value(args[0]);
688 ASSERT(!value->IsTheHole());
689 CONVERT_ARG_CHECKED(Context, context, 1);
690 Handle<String> name(String::cast(args[2]));
691
692 // Initializations are always done in the function context.
693 context = Handle<Context>(context->fcontext());
694
695 int index;
696 PropertyAttributes attributes;
697 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000698 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699 context->Lookup(name, flags, &index, &attributes);
700
701 // The property should always be present. It is always declared
702 // before being initialized through DeclareContextSlot.
703 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
704
705 // If the slot is in the context, we set it but only if it hasn't
706 // been set before.
707 if (index >= 0) {
708 // The constant context slot should always be in the function
709 // context; not in any outer context nor in the arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000710 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711 if (context->get(index)->IsTheHole()) {
712 context->set(index, *value);
713 }
714 return *value;
715 }
716
717 // Otherwise, the slot must be in a JS object extension.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000718 Handle<JSObject> context_ext(JSObject::cast(*holder));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000719
720 // We must initialize the value only if it wasn't initialized
721 // before, e.g. for const declarations in a loop. The property has
722 // the hole value if it wasn't initialized yet. NOTE: We cannot use
723 // GetProperty() to get the current value as it 'unholes' the value.
724 LookupResult lookup;
725 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
726 ASSERT(lookup.IsProperty()); // the property was declared
727 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
728
729 PropertyType type = lookup.type();
730 if (type == FIELD) {
731 FixedArray* properties = context_ext->properties();
732 int index = lookup.GetFieldIndex();
733 if (properties->get(index)->IsTheHole()) {
734 properties->set(index, *value);
735 }
736 } else if (type == NORMAL) {
737 Dictionary* dictionary = context_ext->property_dictionary();
738 int entry = lookup.GetDictionaryEntry();
739 if (dictionary->ValueAt(entry)->IsTheHole()) {
740 dictionary->ValueAtPut(entry, *value);
741 }
742 } else {
743 // We should not reach here. Any real, named property should be
744 // either a field or a dictionary slot.
745 UNREACHABLE();
746 }
747 return *value;
748}
749
750
751static Object* Runtime_RegExpExec(Arguments args) {
752 HandleScope scope;
753 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000754 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
755 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000756 CONVERT_CHECKED(String, raw_subject, args[1]);
757 Handle<String> subject(raw_subject);
758 Handle<Object> index(args[2]);
759 ASSERT(index->IsNumber());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000760 return *RegExpImpl::Exec(regexp, subject, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000761}
762
763
764static Object* Runtime_RegExpExecGlobal(Arguments args) {
765 HandleScope scope;
766 ASSERT(args.length() == 2);
ager@chromium.org236ad962008-09-25 09:45:57 +0000767 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
768 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000769 CONVERT_CHECKED(String, raw_subject, args[1]);
770 Handle<String> subject(raw_subject);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000771 return *RegExpImpl::ExecGlobal(regexp, subject);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000772}
773
774
775static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
776 HandleScope scope;
777 ASSERT(args.length() == 4);
778 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
779 int index = Smi::cast(args[1])->value();
780 Handle<String> pattern = args.at<String>(2);
781 Handle<String> flags = args.at<String>(3);
782
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000783 // Get the RegExp function from the context in the literals array.
784 // This is the RegExp function from the context in which the
785 // function was created. We do not use the RegExp function from the
786 // current global context because this might be the RegExp function
787 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000788 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +0000789 Handle<JSFunction>(
790 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791 // Compute the regular expression literal.
792 bool has_pending_exception;
793 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000794 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
795 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000796 if (has_pending_exception) {
797 ASSERT(Top::has_pending_exception());
798 return Failure::Exception();
799 }
800 literals->set(index, *regexp);
801 return *regexp;
802}
803
804
805static Object* Runtime_FunctionGetName(Arguments args) {
806 NoHandleAllocation ha;
807 ASSERT(args.length() == 1);
808
809 CONVERT_CHECKED(JSFunction, f, args[0]);
810 return f->shared()->name();
811}
812
813
ager@chromium.org236ad962008-09-25 09:45:57 +0000814static Object* Runtime_FunctionSetName(Arguments args) {
815 NoHandleAllocation ha;
816 ASSERT(args.length() == 2);
817
818 CONVERT_CHECKED(JSFunction, f, args[0]);
819 CONVERT_CHECKED(String, name, args[1]);
820 f->shared()->set_name(name);
821 return Heap::undefined_value();
822}
823
824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000825static Object* Runtime_FunctionGetScript(Arguments args) {
826 HandleScope scope;
827 ASSERT(args.length() == 1);
828
829 CONVERT_CHECKED(JSFunction, fun, args[0]);
830 Handle<Object> script = Handle<Object>(fun->shared()->script());
831 if (!script->IsScript()) return Heap::undefined_value();
832
833 return *GetScriptWrapper(Handle<Script>::cast(script));
834}
835
836
837static Object* Runtime_FunctionGetSourceCode(Arguments args) {
838 NoHandleAllocation ha;
839 ASSERT(args.length() == 1);
840
841 CONVERT_CHECKED(JSFunction, f, args[0]);
842 return f->shared()->GetSourceCode();
843}
844
845
846static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
847 NoHandleAllocation ha;
848 ASSERT(args.length() == 1);
849
850 CONVERT_CHECKED(JSFunction, fun, args[0]);
851 int pos = fun->shared()->start_position();
852 return Smi::FromInt(pos);
853}
854
855
856static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
857 NoHandleAllocation ha;
858 ASSERT(args.length() == 2);
859
860 CONVERT_CHECKED(JSFunction, fun, args[0]);
861 CONVERT_CHECKED(String, name, args[1]);
862 fun->SetInstanceClassName(name);
863 return Heap::undefined_value();
864}
865
866
867static Object* Runtime_FunctionSetLength(Arguments args) {
868 NoHandleAllocation ha;
869 ASSERT(args.length() == 2);
870
871 CONVERT_CHECKED(JSFunction, fun, args[0]);
872 CONVERT_CHECKED(Smi, length, args[1]);
873 fun->shared()->set_length(length->value());
874 return length;
875}
876
877
878static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000879 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000880 ASSERT(args.length() == 2);
881
882 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000883 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
884 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885 return args[0]; // return TOS
886}
887
888
889static Object* Runtime_SetCode(Arguments args) {
890 HandleScope scope;
891 ASSERT(args.length() == 2);
892
893 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
894 Handle<JSFunction> target(raw_target);
895 Handle<Object> code = args.at<Object>(1);
896
897 Handle<Context> context(target->context());
898
899 if (!code->IsNull()) {
900 RUNTIME_ASSERT(code->IsJSFunction());
901 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
902 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
903 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
904 return Failure::Exception();
905 }
906 // Set the code, formal parameter count, and the length of the target
907 // function.
908 target->set_code(fun->code());
909 target->shared()->set_length(fun->shared()->length());
910 target->shared()->set_formal_parameter_count(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000911 fun->shared()->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +0000912 // Set the source code of the target function to undefined.
913 // SetCode is only used for built-in constructors like String,
914 // Array, and Object, and some web code
915 // doesn't like seeing source code for constructors.
916 target->shared()->set_script(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917 context = Handle<Context>(fun->context());
918
919 // Make sure we get a fresh copy of the literal vector to avoid
920 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000921 int number_of_literals = fun->NumberOfLiterals();
922 Handle<FixedArray> literals =
923 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000924 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000925 // Insert the object, regexp and array functions in the literals
926 // array prefix. These are the functions that will be used when
927 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +0000928 literals->set(JSFunction::kLiteralGlobalContextIndex,
929 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000931 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932 }
933
934 target->set_context(*context);
935 return *target;
936}
937
938
939static Object* CharCodeAt(String* subject, Object* index) {
940 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000941 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 // Flatten the string. If someone wants to get a char at an index
943 // in a cons string, it is likely that more indices will be
944 // accessed.
945 subject->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000946 if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000947 return Smi::FromInt(subject->Get(i));
948}
949
950
951static Object* Runtime_StringCharCodeAt(Arguments args) {
952 NoHandleAllocation ha;
953 ASSERT(args.length() == 2);
954
955 CONVERT_CHECKED(String, subject, args[0]);
956 Object* index = args[1];
957 return CharCodeAt(subject, index);
958}
959
960
961static Object* Runtime_CharFromCode(Arguments args) {
962 NoHandleAllocation ha;
963 ASSERT(args.length() == 1);
964 uint32_t code;
965 if (Array::IndexFromObject(args[0], &code)) {
966 if (code <= 0xffff) {
967 return Heap::LookupSingleCharacterStringFromCode(code);
968 }
969 }
970 return Heap::empty_string();
971}
972
973
ager@chromium.org7c537e22008-10-16 08:43:32 +0000974// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
975// limit, we can fix the size of tables.
976static const int kBMMaxShift = 0xff;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000977// Reduce alphabet to this size.
978static const int kBMAlphabetSize = 0x100;
979// For patterns below this length, the skip length of Boyer-Moore is too short
980// to compensate for the algorithmic overhead compared to simple brute force.
981static const int kBMMinPatternLength = 5;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000982
ager@chromium.org7c537e22008-10-16 08:43:32 +0000983// Holds the two buffers used by Boyer-Moore string search's Good Suffix
984// shift. Only allows the last kBMMaxShift characters of the needle
985// to be indexed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000986class BMGoodSuffixBuffers {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000987 public:
988 BMGoodSuffixBuffers() {}
989 inline void init(int needle_length) {
990 ASSERT(needle_length > 1);
991 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
992 int len = needle_length - start;
993 biased_suffixes_ = suffixes_ - start;
994 biased_good_suffix_shift_ = good_suffix_shift_ - start;
995 for (int i = 0; i <= len; i++) {
996 good_suffix_shift_[i] = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000998 }
999 inline int& suffix(int index) {
1000 ASSERT(biased_suffixes_ + index >= suffixes_);
1001 return biased_suffixes_[index];
1002 }
1003 inline int& shift(int index) {
1004 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
1005 return biased_good_suffix_shift_[index];
1006 }
1007 private:
1008 int suffixes_[kBMMaxShift + 1];
1009 int good_suffix_shift_[kBMMaxShift + 1];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001010 int* biased_suffixes_;
1011 int* biased_good_suffix_shift_;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001012 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
1013};
1014
1015// buffers reused by BoyerMoore
1016static int bad_char_occurence[kBMAlphabetSize];
1017static BMGoodSuffixBuffers bmgs_buffers;
1018
1019// Compute the bad-char table for Boyer-Moore in the static buffer.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001020template <typename pchar>
1021static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern,
1022 int start) {
1023 // Run forwards to populate bad_char_table, so that *last* instance
1024 // of character equivalence class is the one registered.
1025 // Notice: Doesn't include the last character.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001026 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
1027 : kBMAlphabetSize;
1028 if (start == 0) { // All patterns less than kBMMaxShift in length.
1029 memset(bad_char_occurence, -1, table_size * sizeof(*bad_char_occurence));
1030 } else {
1031 for (int i = 0; i < table_size; i++) {
1032 bad_char_occurence[i] = start - 1;
1033 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001034 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001035 for (int i = start; i < pattern.length() - 1; i++) {
1036 pchar c = pattern[i];
1037 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
1038 bad_char_occurence[bucket] = i;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001039 }
1040}
1041
1042template <typename pchar>
1043static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001044 int start) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001045 int m = pattern.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001046 int len = m - start;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001047 // Compute Good Suffix tables.
1048 bmgs_buffers.init(m);
1049
1050 bmgs_buffers.shift(m-1) = 1;
1051 bmgs_buffers.suffix(m) = m + 1;
1052 pchar last_char = pattern[m - 1];
1053 int suffix = m + 1;
1054 for (int i = m; i > start;) {
1055 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
1056 if (bmgs_buffers.shift(suffix) == len) {
1057 bmgs_buffers.shift(suffix) = suffix - i;
1058 }
1059 suffix = bmgs_buffers.suffix(suffix);
1060 }
1061 i--;
1062 suffix--;
1063 bmgs_buffers.suffix(i) = suffix;
1064 if (suffix == m) {
1065 // No suffix to extend, so we check against last_char only.
1066 while (i > start && pattern[i - 1] != last_char) {
1067 if (bmgs_buffers.shift(m) == len) {
1068 bmgs_buffers.shift(m) = m - i;
1069 }
1070 i--;
1071 bmgs_buffers.suffix(i) = m;
1072 }
1073 if (i > start) {
1074 i--;
1075 suffix--;
1076 bmgs_buffers.suffix(i) = suffix;
1077 }
1078 }
1079 }
1080 if (suffix < m) {
1081 for (int i = start; i <= m; i++) {
1082 if (bmgs_buffers.shift(i) == len) {
1083 bmgs_buffers.shift(i) = suffix - start;
1084 }
1085 if (i == suffix) {
1086 suffix = bmgs_buffers.suffix(suffix);
1087 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088 }
1089 }
1090}
1091
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001092template <typename schar, typename pchar>
1093static inline int CharOccurence(int char_code) {
1094 if (sizeof(schar) == 1) {
1095 return bad_char_occurence[char_code];
1096 }
1097 if (sizeof(pchar) == 1) {
1098 if (char_code > String::kMaxAsciiCharCode) {
1099 return -1;
1100 }
1101 return bad_char_occurence[char_code];
1102 }
1103 return bad_char_occurence[char_code % kBMAlphabetSize];
1104}
1105
1106// Restricted simplified Boyer-Moore string matching. Restricts tables to a
ager@chromium.org7c537e22008-10-16 08:43:32 +00001107// suffix of long pattern strings and handles only equivalence classes
1108// of the full alphabet. This allows us to ensure that tables take only
1109// a fixed amount of space.
1110template <typename schar, typename pchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001111static int BoyerMooreSimplified(Vector<const schar> subject,
1112 Vector<const pchar> pattern,
1113 int start_index,
1114 bool* complete) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001115 int n = subject.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001116 int m = pattern.length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00001117 // Only preprocess at most kBMMaxShift last characters of pattern.
1118 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119
ager@chromium.org7c537e22008-10-16 08:43:32 +00001120 BoyerMoorePopulateBadCharTable(pattern, start);
1121
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001122 int badness = -m; // How bad we are doing without a good-suffix table.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001123 int idx; // No matches found prior to this index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001124 pchar last_char = pattern[m - 1];
ager@chromium.org7c537e22008-10-16 08:43:32 +00001125 // Perform search
1126 for (idx = start_index; idx <= n - m;) {
1127 int j = m - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001128 int c;
1129 while (last_char != (c = subject[idx + j])) {
1130 int bc_occ = CharOccurence<schar, pchar>(c);
1131 int shift = j - bc_occ;
1132 idx += shift;
1133 badness += 1 - shift; // at most zero, so badness cannot increase.
1134 if (idx > n - m) {
1135 *complete = true;
1136 return -1;
1137 }
1138 }
1139 j--;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001140 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1141 if (j < 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001142 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001143 return idx;
1144 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001145 int bc_occ = CharOccurence<schar, pchar>(c);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001146 int shift = bc_occ < j ? j - bc_occ : 1;
1147 idx += shift;
1148 // Badness increases by the number of characters we have
1149 // checked, and decreases by the number of characters we
1150 // can skip by shifting. It's a measure of how we are doing
1151 // compared to reading each character exactly once.
1152 badness += (m - j) - shift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001153 if (badness > 0) {
1154 *complete = false;
1155 return idx;
1156 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001157 }
1158 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001159 *complete = true;
1160 return -1;
1161}
ager@chromium.org7c537e22008-10-16 08:43:32 +00001162
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001163
1164template <typename schar, typename pchar>
1165static int BoyerMooreIndexOf(Vector<const schar> subject,
1166 Vector<const pchar> pattern,
1167 int idx) {
1168 int n = subject.length();
1169 int m = pattern.length();
1170 // Only preprocess at most kBMMaxShift last characters of pattern.
1171 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
1172
1173 // Build the Good Suffix table and continue searching.
1174 BoyerMoorePopulateGoodSuffixTable(pattern, start);
1175 pchar last_char = pattern[m - 1];
1176 // Continue search from i.
1177 do {
1178 int j = m - 1;
1179 schar c;
1180 while (last_char != (c = subject[idx + j])) {
1181 int shift = j - CharOccurence<schar, pchar>(c);
1182 idx += shift;
1183 if (idx > n - m) {
1184 return -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001185 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001186 }
1187 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1188 if (j < 0) {
1189 return idx;
1190 } else if (j < start) {
1191 // we have matched more than our tables allow us to be smart about.
1192 idx += 1;
1193 } else {
1194 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift.
1195 int bc_occ = CharOccurence<schar, pchar>(c);
1196 int shift = j - bc_occ; // Bad-char shift.
1197 shift = (gs_shift > shift) ? gs_shift : shift;
1198 idx += shift;
1199 }
1200 } while (idx <= n - m);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001201
1202 return -1;
1203}
1204
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001205
1206template <typename schar>
ager@chromium.org7c537e22008-10-16 08:43:32 +00001207static int SingleCharIndexOf(Vector<const schar> string,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001208 uc16 pattern_char,
ager@chromium.org7c537e22008-10-16 08:43:32 +00001209 int start_index) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001210 if (sizeof(schar) == 1 && pattern_char > String::kMaxAsciiCharCode) {
1211 return -1;
1212 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001213 for (int i = start_index, n = string.length(); i < n; i++) {
1214 if (pattern_char == string[i]) {
1215 return i;
1216 }
1217 }
1218 return -1;
1219}
1220
1221// Trivial string search for shorter strings.
1222// On return, if "complete" is set to true, the return value is the
1223// final result of searching for the patter in the subject.
1224// If "complete" is set to false, the return value is the index where
1225// further checking should start, i.e., it's guaranteed that the pattern
1226// does not occur at a position prior to the returned index.
1227template <typename pchar, typename schar>
1228static int SimpleIndexOf(Vector<const schar> subject,
1229 Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001230 int idx,
1231 bool* complete) {
1232 // Badness is a count of how much work we have done. When we have
1233 // done enough work we decide it's probably worth switching to a better
1234 // algorithm.
1235 int badness = -10 - (pattern.length() << 2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001236 // We know our pattern is at least 2 characters, we cache the first so
1237 // the common case of the first character not matching is faster.
1238 pchar pattern_first_char = pattern[0];
1239
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001240 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1241 badness++;
1242 if (badness > 0) {
1243 *complete = false;
1244 return (i);
1245 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001246 if (subject[i] != pattern_first_char) continue;
1247 int j = 1;
1248 do {
1249 if (pattern[j] != subject[i+j]) {
1250 break;
1251 }
1252 j++;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001253 } while (j < pattern.length());
1254 if (j == pattern.length()) {
1255 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001256 return i;
1257 }
1258 badness += j;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001259 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001260 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001261 return -1;
1262}
1263
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001264// Simple indexOf that never bails out. For short patterns only.
1265template <typename pchar, typename schar>
1266static int SimpleIndexOf(Vector<const schar> subject,
1267 Vector<const pchar> pattern,
1268 int idx) {
1269 pchar pattern_first_char = pattern[0];
1270 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1271 if (subject[i] != pattern_first_char) continue;
1272 int j = 1;
1273 do {
1274 if (pattern[j] != subject[i+j]) {
1275 break;
1276 }
1277 j++;
1278 } while (j < pattern.length());
1279 if (j == pattern.length()) {
1280 return i;
1281 }
1282 }
1283 return -1;
1284}
1285
1286
1287// Dispatch to different algorithms.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001288template <typename schar, typename pchar>
1289static int StringMatchStrategy(Vector<const schar> sub,
1290 Vector<const pchar> pat,
1291 int start_index) {
1292 ASSERT(pat.length() > 1);
1293
1294 // We have an ASCII haystack and a non-ASCII needle. Check if there
1295 // really is a non-ASCII character in the needle and bail out if there
1296 // is.
1297 if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
1298 for (int i = 0; i < pat.length(); i++) {
1299 uc16 c = pat[i];
1300 if (c > String::kMaxAsciiCharCode) {
1301 return -1;
1302 }
1303 }
1304 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001305 if (pat.length() < kBMMinPatternLength) {
1306 // We don't believe fancy searching can ever be more efficient.
1307 // The max shift of Boyer-Moore on a pattern of this length does
1308 // not compensate for the overhead.
1309 return SimpleIndexOf(sub, pat, start_index);
1310 }
1311 // Try algorithms in order of increasing setup cost and expected performance.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001312 bool complete;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001313 int idx = SimpleIndexOf(sub, pat, start_index, &complete);
1314 if (complete) return idx;
1315 idx = BoyerMooreSimplified(sub, pat, idx, &complete);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001316 if (complete) return idx;
1317 return BoyerMooreIndexOf(sub, pat, idx);
1318}
1319
1320// Perform string match of pattern on subject, starting at start index.
1321// Caller must ensure that 0 <= start_index <= sub->length(),
1322// and should check that pat->length() + start_index <= sub->length()
1323int Runtime::StringMatch(Handle<String> sub,
1324 Handle<String> pat,
1325 int start_index) {
1326 ASSERT(0 <= start_index);
1327 ASSERT(start_index <= sub->length());
1328
ager@chromium.org236ad962008-09-25 09:45:57 +00001329 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001330 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331
ager@chromium.org7c537e22008-10-16 08:43:32 +00001332 int subject_length = sub->length();
1333 if (start_index + pattern_length > subject_length) return -1;
1334
1335 FlattenString(sub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 // Searching for one specific character is common. For one
ager@chromium.org7c537e22008-10-16 08:43:32 +00001337 // character patterns linear search is necessary, so any smart
1338 // algorithm is unnecessary overhead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 if (pattern_length == 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001340 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1341 if (sub->is_ascii_representation()) {
1342 return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001343 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001344 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 }
1346
ager@chromium.org7c537e22008-10-16 08:43:32 +00001347 FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00001348
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1350 // dispatch on type of strings
1351 if (pat->is_ascii_representation()) {
1352 Vector<const char> pat_vector = pat->ToAsciiVector();
1353 if (sub->is_ascii_representation()) {
1354 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001355 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001356 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001357 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001358 Vector<const uc16> pat_vector = pat->ToUC16Vector();
1359 if (sub->is_ascii_representation()) {
1360 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001362 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001363}
1364
1365
1366static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001367 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001368 ASSERT(args.length() == 3);
1369
ager@chromium.org7c537e22008-10-16 08:43:32 +00001370 CONVERT_ARG_CHECKED(String, sub, 0);
1371 CONVERT_ARG_CHECKED(String, pat, 1);
1372
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001373 Object* index = args[2];
1374 uint32_t start_index;
1375 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1376
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 int position = Runtime::StringMatch(sub, pat, start_index);
1378 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379}
1380
1381
1382static Object* Runtime_StringLastIndexOf(Arguments args) {
1383 NoHandleAllocation ha;
1384 ASSERT(args.length() == 3);
1385
1386 CONVERT_CHECKED(String, sub, args[0]);
1387 CONVERT_CHECKED(String, pat, args[1]);
1388 Object* index = args[2];
1389
1390 sub->TryFlatten();
1391 pat->TryFlatten();
1392
1393 uint32_t start_index;
1394 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1395
1396 uint32_t pattern_length = pat->length();
1397 uint32_t sub_length = sub->length();
1398
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001399 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001401 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402
1403 for (int i = start_index; i >= 0; i--) {
1404 bool found = true;
1405 for (uint32_t j = 0; j < pattern_length; j++) {
1406 if (sub->Get(i + j) != pat->Get(j)) {
1407 found = false;
1408 break;
1409 }
1410 }
1411 if (found) return Smi::FromInt(i);
1412 }
1413
1414 return Smi::FromInt(-1);
1415}
1416
1417
1418static Object* Runtime_StringLocaleCompare(Arguments args) {
1419 NoHandleAllocation ha;
1420 ASSERT(args.length() == 2);
1421
1422 CONVERT_CHECKED(String, str1, args[0]);
1423 CONVERT_CHECKED(String, str2, args[1]);
1424
1425 if (str1 == str2) return Smi::FromInt(0); // Equal.
1426 int str1_length = str1->length();
1427 int str2_length = str2->length();
1428
1429 // Decide trivial cases without flattening.
1430 if (str1_length == 0) {
1431 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1432 return Smi::FromInt(-str2_length);
1433 } else {
1434 if (str2_length == 0) return Smi::FromInt(str1_length);
1435 }
1436
1437 int end = str1_length < str2_length ? str1_length : str2_length;
1438
1439 // No need to flatten if we are going to find the answer on the first
1440 // character. At this point we know there is at least one character
1441 // in each string, due to the trivial case handling above.
1442 int d = str1->Get(0) - str2->Get(0);
1443 if (d != 0) return Smi::FromInt(d);
1444
1445 str1->TryFlatten();
1446 str2->TryFlatten();
1447
1448 static StringInputBuffer buf1;
1449 static StringInputBuffer buf2;
1450
1451 buf1.Reset(str1);
1452 buf2.Reset(str2);
1453
1454 for (int i = 0; i < end; i++) {
1455 uint16_t char1 = buf1.GetNext();
1456 uint16_t char2 = buf2.GetNext();
1457 if (char1 != char2) return Smi::FromInt(char1 - char2);
1458 }
1459
1460 return Smi::FromInt(str1_length - str2_length);
1461}
1462
1463
1464static Object* Runtime_StringSlice(Arguments args) {
1465 NoHandleAllocation ha;
1466 ASSERT(args.length() == 3);
1467
1468 CONVERT_CHECKED(String, value, args[0]);
1469 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1470 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1471
1472 int start = FastD2I(from_number);
1473 int end = FastD2I(to_number);
1474
1475 RUNTIME_ASSERT(end >= start);
1476 RUNTIME_ASSERT(start >= 0);
1477 RUNTIME_ASSERT(end <= value->length());
1478 return value->Slice(start, end);
1479}
1480
1481
1482static Object* Runtime_NumberToRadixString(Arguments args) {
1483 NoHandleAllocation ha;
1484 ASSERT(args.length() == 2);
1485
1486 CONVERT_DOUBLE_CHECKED(value, args[0]);
1487 if (isnan(value)) {
1488 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1489 }
1490 if (isinf(value)) {
1491 if (value < 0) {
1492 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1493 }
1494 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1495 }
1496 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1497 int radix = FastD2I(radix_number);
1498 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1499 char* str = DoubleToRadixCString(value, radix);
1500 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1501 DeleteArray(str);
1502 return result;
1503}
1504
1505
1506static Object* Runtime_NumberToFixed(Arguments args) {
1507 NoHandleAllocation ha;
1508 ASSERT(args.length() == 2);
1509
1510 CONVERT_DOUBLE_CHECKED(value, args[0]);
1511 if (isnan(value)) {
1512 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1513 }
1514 if (isinf(value)) {
1515 if (value < 0) {
1516 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1517 }
1518 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1519 }
1520 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1521 int f = FastD2I(f_number);
1522 RUNTIME_ASSERT(f >= 0);
1523 char* str = DoubleToFixedCString(value, f);
1524 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1525 DeleteArray(str);
1526 return res;
1527}
1528
1529
1530static Object* Runtime_NumberToExponential(Arguments args) {
1531 NoHandleAllocation ha;
1532 ASSERT(args.length() == 2);
1533
1534 CONVERT_DOUBLE_CHECKED(value, args[0]);
1535 if (isnan(value)) {
1536 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1537 }
1538 if (isinf(value)) {
1539 if (value < 0) {
1540 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1541 }
1542 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1543 }
1544 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1545 int f = FastD2I(f_number);
1546 RUNTIME_ASSERT(f >= -1 && f <= 20);
1547 char* str = DoubleToExponentialCString(value, f);
1548 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1549 DeleteArray(str);
1550 return res;
1551}
1552
1553
1554static Object* Runtime_NumberToPrecision(Arguments args) {
1555 NoHandleAllocation ha;
1556 ASSERT(args.length() == 2);
1557
1558 CONVERT_DOUBLE_CHECKED(value, args[0]);
1559 if (isnan(value)) {
1560 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1561 }
1562 if (isinf(value)) {
1563 if (value < 0) {
1564 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1565 }
1566 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1567 }
1568 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1569 int f = FastD2I(f_number);
1570 RUNTIME_ASSERT(f >= 1 && f <= 21);
1571 char* str = DoubleToPrecisionCString(value, f);
1572 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1573 DeleteArray(str);
1574 return res;
1575}
1576
1577
1578// Returns a single character string where first character equals
1579// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001580static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 if (index < static_cast<uint32_t>(string->length())) {
1582 string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001583 return LookupSingleCharacterStringFromCode(string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001584 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001585 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586}
1587
1588
1589Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1590 // Handle [] indexing on Strings
1591 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001592 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1593 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 }
1595
1596 // Handle [] indexing on String objects
1597 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001598 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1599 Handle<Object> result =
1600 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1601 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001602 }
1603
1604 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001605 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 return prototype->GetElement(index);
1607 }
1608
1609 return object->GetElement(index);
1610}
1611
1612
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001613Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1614 HandleScope scope;
1615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001617 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 Handle<Object> error =
1619 Factory::NewTypeError("non_object_property_load",
1620 HandleVector(args, 2));
1621 return Top::Throw(*error);
1622 }
1623
1624 // Check if the given key is an array index.
1625 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001626 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001627 return GetElementOrCharAt(object, index);
1628 }
1629
1630 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001631 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001632 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001633 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001634 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 bool has_pending_exception = false;
1636 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001637 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001638 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001639 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001640 }
1641
1642 // Check if the name is trivially convertable to an index and get
1643 // the element if so.
1644 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 return GetElementOrCharAt(object, index);
1646 } else {
1647 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001648 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649 }
1650}
1651
1652
1653static Object* Runtime_GetProperty(Arguments args) {
1654 NoHandleAllocation ha;
1655 ASSERT(args.length() == 2);
1656
1657 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001658 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001659
1660 return Runtime::GetObjectProperty(object, key);
1661}
1662
1663
ager@chromium.org7c537e22008-10-16 08:43:32 +00001664
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001665// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001666static Object* Runtime_KeyedGetProperty(Arguments args) {
1667 NoHandleAllocation ha;
1668 ASSERT(args.length() == 2);
1669
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001670 // Fast cases for getting named properties of the receiver JSObject
1671 // itself. The global proxy objects has to be excluded since
1672 // LocalLookup on the global proxy object can return a valid result
1673 // eventhough the global proxy object never has properties. This is
1674 // the case because the global proxy object forwards everything to
1675 // its hidden prototype including local lookups.
1676 if (args[0]->IsJSObject() &&
1677 !args[0]->IsJSGlobalProxy() &&
1678 args[1]->IsString()) {
1679 JSObject* receiver = JSObject::cast(args[0]);
1680 String* key = String::cast(args[1]);
1681 if (receiver->HasFastProperties()) {
1682 // Attempt to use lookup cache.
1683 Object* obj = Heap::GetKeyedLookupCache();
1684 if (obj->IsFailure()) return obj;
1685 LookupCache* cache = LookupCache::cast(obj);
1686 Map* receiver_map = receiver->map();
1687 int offset = cache->Lookup(receiver_map, key);
1688 if (offset != LookupCache::kNotFound) {
1689 Object* value = receiver->FastPropertyAt(offset);
1690 return value->IsTheHole() ? Heap::undefined_value() : value;
1691 }
1692 // Lookup cache miss. Perform lookup and update the cache if
1693 // appropriate.
1694 LookupResult result;
1695 receiver->LocalLookup(key, &result);
1696 if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
1697 int offset = result.GetFieldIndex();
1698 Object* obj = cache->Put(receiver_map, key, offset);
1699 if (obj->IsFailure()) return obj;
1700 Heap::SetKeyedLookupCache(LookupCache::cast(obj));
1701 Object* value = receiver->FastPropertyAt(offset);
1702 return value->IsTheHole() ? Heap::undefined_value() : value;
1703 }
1704 } else {
1705 // Attempt dictionary lookup.
1706 Dictionary* dictionary = receiver->property_dictionary();
1707 int entry = dictionary->FindStringEntry(key);
1708 if ((entry != DescriptorArray::kNotFound) &&
1709 (dictionary->DetailsAt(entry).type() == NORMAL)) {
1710 return dictionary->ValueAt(entry);
1711 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001712 }
1713 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001714
1715 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001716 return Runtime::GetObjectProperty(args.at<Object>(0),
1717 args.at<Object>(1));
1718}
1719
1720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001721Object* Runtime::SetObjectProperty(Handle<Object> object,
1722 Handle<Object> key,
1723 Handle<Object> value,
1724 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001725 HandleScope scope;
1726
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001728 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001729 Handle<Object> error =
1730 Factory::NewTypeError("non_object_property_store",
1731 HandleVector(args, 2));
1732 return Top::Throw(*error);
1733 }
1734
1735 // If the object isn't a JavaScript object, we ignore the store.
1736 if (!object->IsJSObject()) return *value;
1737
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001738 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740 // Check if the given key is an array index.
1741 uint32_t index;
1742 if (Array::IndexFromObject(*key, &index)) {
1743 ASSERT(attr == NONE);
1744
1745 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1746 // of a string using [] notation. We need to support this too in
1747 // JavaScript.
1748 // In the case of a String object we just need to redirect the assignment to
1749 // the underlying string if the index is in range. Since the underlying
1750 // string does nothing with the assignment then we can ignore such
1751 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001752 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001753 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001754 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001755
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001756 Handle<Object> result = SetElement(js_object, index, value);
1757 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001758 return *value;
1759 }
1760
1761 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001762 Handle<Object> result;
1763 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001764 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001765 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001766 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001767 Handle<String> key_string = Handle<String>::cast(key);
1768 key_string->TryFlatten();
1769 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001770 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001771 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 return *value;
1773 }
1774
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001775 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001776 bool has_pending_exception = false;
1777 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1778 if (has_pending_exception) return Failure::Exception();
1779 Handle<String> name = Handle<String>::cast(converted);
1780
1781 if (name->AsArrayIndex(&index)) {
1782 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001783 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001785 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001786 }
1787}
1788
1789
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001790static Object* Runtime_SetProperty(Arguments args) {
1791 NoHandleAllocation ha;
1792 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1793
1794 Handle<Object> object = args.at<Object>(0);
1795 Handle<Object> key = args.at<Object>(1);
1796 Handle<Object> value = args.at<Object>(2);
1797
1798 // Compute attributes.
1799 PropertyAttributes attributes = NONE;
1800 if (args.length() == 4) {
1801 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001804 RUNTIME_ASSERT(
1805 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1806 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807 }
1808 return Runtime::SetObjectProperty(object, key, value, attributes);
1809}
1810
1811
1812// Set a local property, even if it is READ_ONLY. If the property does not
1813// exist, it will be added with attributes NONE.
1814static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1815 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001816 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 CONVERT_CHECKED(JSObject, object, args[0]);
1818 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001819 // Compute attributes.
1820 PropertyAttributes attributes = NONE;
1821 if (args.length() == 4) {
1822 CONVERT_CHECKED(Smi, value_obj, args[3]);
1823 int unchecked_value = value_obj->value();
1824 // Only attribute bits should be set.
1825 RUNTIME_ASSERT(
1826 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1827 attributes = static_cast<PropertyAttributes>(unchecked_value);
1828 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001829
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001830 return object->
1831 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001832}
1833
1834
1835static Object* Runtime_DeleteProperty(Arguments args) {
1836 NoHandleAllocation ha;
1837 ASSERT(args.length() == 2);
1838
1839 CONVERT_CHECKED(JSObject, object, args[0]);
1840 CONVERT_CHECKED(String, key, args[1]);
1841 return object->DeleteProperty(key);
1842}
1843
1844
1845static Object* Runtime_HasLocalProperty(Arguments args) {
1846 NoHandleAllocation ha;
1847 ASSERT(args.length() == 2);
1848 CONVERT_CHECKED(String, key, args[1]);
1849
1850 // Only JS objects can have properties.
1851 if (args[0]->IsJSObject()) {
1852 JSObject* object = JSObject::cast(args[0]);
1853 if (object->HasLocalProperty(key)) return Heap::true_value();
1854 } else if (args[0]->IsString()) {
1855 // Well, there is one exception: Handle [] on strings.
1856 uint32_t index;
1857 if (key->AsArrayIndex(&index)) {
1858 String* string = String::cast(args[0]);
1859 if (index < static_cast<uint32_t>(string->length()))
1860 return Heap::true_value();
1861 }
1862 }
1863 return Heap::false_value();
1864}
1865
1866
1867static Object* Runtime_HasProperty(Arguments args) {
1868 NoHandleAllocation na;
1869 ASSERT(args.length() == 2);
1870
1871 // Only JS objects can have properties.
1872 if (args[0]->IsJSObject()) {
1873 JSObject* object = JSObject::cast(args[0]);
1874 CONVERT_CHECKED(String, key, args[1]);
1875 if (object->HasProperty(key)) return Heap::true_value();
1876 }
1877 return Heap::false_value();
1878}
1879
1880
1881static Object* Runtime_HasElement(Arguments args) {
1882 NoHandleAllocation na;
1883 ASSERT(args.length() == 2);
1884
1885 // Only JS objects can have elements.
1886 if (args[0]->IsJSObject()) {
1887 JSObject* object = JSObject::cast(args[0]);
1888 CONVERT_CHECKED(Smi, index_obj, args[1]);
1889 uint32_t index = index_obj->value();
1890 if (object->HasElement(index)) return Heap::true_value();
1891 }
1892 return Heap::false_value();
1893}
1894
1895
1896static Object* Runtime_IsPropertyEnumerable(Arguments args) {
1897 NoHandleAllocation ha;
1898 ASSERT(args.length() == 2);
1899
1900 CONVERT_CHECKED(JSObject, object, args[0]);
1901 CONVERT_CHECKED(String, key, args[1]);
1902
1903 uint32_t index;
1904 if (key->AsArrayIndex(&index)) {
1905 return Heap::ToBoolean(object->HasElement(index));
1906 }
1907
1908 LookupResult result;
1909 object->LocalLookup(key, &result);
1910 if (!result.IsProperty()) return Heap::false_value();
1911 return Heap::ToBoolean(!result.IsDontEnum());
1912}
1913
1914
1915static Object* Runtime_GetPropertyNames(Arguments args) {
1916 HandleScope scope;
1917 ASSERT(args.length() == 1);
1918
1919 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1920 Handle<JSObject> object(raw_object);
1921 return *GetKeysFor(object);
1922}
1923
1924
1925// Returns either a FixedArray as Runtime_GetPropertyNames,
1926// or, if the given object has an enum cache that contains
1927// all enumerable properties of the object and its prototypes
1928// have none, the map of the object. This is used to speed up
1929// the check for deletions during a for-in.
1930static Object* Runtime_GetPropertyNamesFast(Arguments args) {
1931 ASSERT(args.length() == 1);
1932
1933 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1934
1935 if (raw_object->IsSimpleEnum()) return raw_object->map();
1936
1937 HandleScope scope;
1938 Handle<JSObject> object(raw_object);
1939 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
1940
1941 // Test again, since cache may have been built by preceding call.
1942 if (object->IsSimpleEnum()) return object->map();
1943
1944 return *content;
1945}
1946
1947
1948static Object* Runtime_GetArgumentsProperty(Arguments args) {
1949 NoHandleAllocation ha;
1950 ASSERT(args.length() == 1);
1951
1952 // Compute the frame holding the arguments.
1953 JavaScriptFrameIterator it;
1954 it.AdvanceToArgumentsFrame();
1955 JavaScriptFrame* frame = it.frame();
1956
1957 // Get the actual number of provided arguments.
1958 const uint32_t n = frame->GetProvidedParametersCount();
1959
1960 // Try to convert the key to an index. If successful and within
1961 // index return the the argument from the frame.
1962 uint32_t index;
1963 if (Array::IndexFromObject(args[0], &index) && index < n) {
1964 return frame->GetParameter(index);
1965 }
1966
1967 // Convert the key to a string.
1968 HandleScope scope;
1969 bool exception = false;
1970 Handle<Object> converted =
1971 Execution::ToString(args.at<Object>(0), &exception);
1972 if (exception) return Failure::Exception();
1973 Handle<String> key = Handle<String>::cast(converted);
1974
1975 // Try to convert the string key into an array index.
1976 if (key->AsArrayIndex(&index)) {
1977 if (index < n) {
1978 return frame->GetParameter(index);
1979 } else {
1980 return Top::initial_object_prototype()->GetElement(index);
1981 }
1982 }
1983
1984 // Handle special arguments properties.
1985 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
1986 if (key->Equals(Heap::callee_symbol())) return frame->function();
1987
1988 // Lookup in the initial Object.prototype object.
1989 return Top::initial_object_prototype()->GetProperty(*key);
1990}
1991
1992
1993static Object* Runtime_ToBool(Arguments args) {
1994 NoHandleAllocation ha;
1995 ASSERT(args.length() == 1);
1996
1997 return args[0]->ToBoolean();
1998}
1999
2000
2001// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
2002// Possible optimizations: put the type string into the oddballs.
2003static Object* Runtime_Typeof(Arguments args) {
2004 NoHandleAllocation ha;
2005
2006 Object* obj = args[0];
2007 if (obj->IsNumber()) return Heap::number_symbol();
2008 HeapObject* heap_obj = HeapObject::cast(obj);
2009
2010 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002011 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002012
2013 InstanceType instance_type = heap_obj->map()->instance_type();
2014 if (instance_type < FIRST_NONSTRING_TYPE) {
2015 return Heap::string_symbol();
2016 }
2017
2018 switch (instance_type) {
2019 case ODDBALL_TYPE:
2020 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
2021 return Heap::boolean_symbol();
2022 }
2023 if (heap_obj->IsNull()) {
2024 return Heap::object_symbol();
2025 }
2026 ASSERT(heap_obj->IsUndefined());
2027 return Heap::undefined_symbol();
2028 case JS_FUNCTION_TYPE:
2029 return Heap::function_symbol();
2030 default:
2031 // For any kind of object not handled above, the spec rule for
2032 // host objects gives that it is okay to return "object"
2033 return Heap::object_symbol();
2034 }
2035}
2036
2037
2038static Object* Runtime_StringToNumber(Arguments args) {
2039 NoHandleAllocation ha;
2040 ASSERT(args.length() == 1);
2041 CONVERT_CHECKED(String, subject, args[0]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002042 subject->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002043 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
2044}
2045
2046
2047static Object* Runtime_StringFromCharCodeArray(Arguments args) {
2048 NoHandleAllocation ha;
2049 ASSERT(args.length() == 1);
2050
2051 CONVERT_CHECKED(JSArray, codes, args[0]);
2052 int length = Smi::cast(codes->length())->value();
2053
2054 // Check if the string can be ASCII.
2055 int i;
2056 for (i = 0; i < length; i++) {
2057 Object* element = codes->GetElement(i);
2058 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2059 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
2060 break;
2061 }
2062
2063 Object* object = NULL;
2064 if (i == length) { // The string is ASCII.
2065 object = Heap::AllocateRawAsciiString(length);
2066 } else { // The string is not ASCII.
2067 object = Heap::AllocateRawTwoByteString(length);
2068 }
2069
2070 if (object->IsFailure()) return object;
2071 String* result = String::cast(object);
2072 for (int i = 0; i < length; i++) {
2073 Object* element = codes->GetElement(i);
2074 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2075 result->Set(i, chr & 0xffff);
2076 }
2077 return result;
2078}
2079
2080
2081// kNotEscaped is generated by the following:
2082//
2083// #!/bin/perl
2084// for (my $i = 0; $i < 256; $i++) {
2085// print "\n" if $i % 16 == 0;
2086// my $c = chr($i);
2087// my $escaped = 1;
2088// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
2089// print $escaped ? "0, " : "1, ";
2090// }
2091
2092
2093static bool IsNotEscaped(uint16_t character) {
2094 // Only for 8 bit characters, the rest are always escaped (in a different way)
2095 ASSERT(character < 256);
2096 static const char kNotEscaped[256] = {
2097 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2098 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2099 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
2100 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
2101 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2102 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
2103 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2104 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
2105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2113 };
2114 return kNotEscaped[character] != 0;
2115}
2116
2117
2118static Object* Runtime_URIEscape(Arguments args) {
2119 const char hex_chars[] = "0123456789ABCDEF";
2120 NoHandleAllocation ha;
2121 ASSERT(args.length() == 1);
2122 CONVERT_CHECKED(String, source, args[0]);
2123
2124 source->TryFlatten();
2125
2126 int escaped_length = 0;
2127 int length = source->length();
2128 {
2129 Access<StringInputBuffer> buffer(&string_input_buffer);
2130 buffer->Reset(source);
2131 while (buffer->has_more()) {
2132 uint16_t character = buffer->GetNext();
2133 if (character >= 256) {
2134 escaped_length += 6;
2135 } else if (IsNotEscaped(character)) {
2136 escaped_length++;
2137 } else {
2138 escaped_length += 3;
2139 }
2140 // We don't allow strings that are longer than Smi range.
2141 if (!Smi::IsValid(escaped_length)) {
2142 Top::context()->mark_out_of_memory();
2143 return Failure::OutOfMemoryException();
2144 }
2145 }
2146 }
2147 // No length change implies no change. Return original string if no change.
2148 if (escaped_length == length) {
2149 return source;
2150 }
2151 Object* o = Heap::AllocateRawAsciiString(escaped_length);
2152 if (o->IsFailure()) return o;
2153 String* destination = String::cast(o);
2154 int dest_position = 0;
2155
2156 Access<StringInputBuffer> buffer(&string_input_buffer);
2157 buffer->Rewind();
2158 while (buffer->has_more()) {
2159 uint16_t character = buffer->GetNext();
2160 if (character >= 256) {
2161 destination->Set(dest_position, '%');
2162 destination->Set(dest_position+1, 'u');
2163 destination->Set(dest_position+2, hex_chars[character >> 12]);
2164 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
2165 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
2166 destination->Set(dest_position+5, hex_chars[character & 0xf]);
2167 dest_position += 6;
2168 } else if (IsNotEscaped(character)) {
2169 destination->Set(dest_position, character);
2170 dest_position++;
2171 } else {
2172 destination->Set(dest_position, '%');
2173 destination->Set(dest_position+1, hex_chars[character >> 4]);
2174 destination->Set(dest_position+2, hex_chars[character & 0xf]);
2175 dest_position += 3;
2176 }
2177 }
2178 return destination;
2179}
2180
2181
2182static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
2183 static const signed char kHexValue['g'] = {
2184 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2185 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2186 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2187 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
2188 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2189 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2190 -1, 10, 11, 12, 13, 14, 15 };
2191
2192 if (character1 > 'f') return -1;
2193 int hi = kHexValue[character1];
2194 if (hi == -1) return -1;
2195 if (character2 > 'f') return -1;
2196 int lo = kHexValue[character2];
2197 if (lo == -1) return -1;
2198 return (hi << 4) + lo;
2199}
2200
2201
2202static inline int Unescape(String* source, int i, int length, int* step) {
2203 uint16_t character = source->Get(i);
2204 int32_t hi, lo;
2205 if (character == '%' &&
2206 i <= length - 6 &&
2207 source->Get(i + 1) == 'u' &&
2208 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
2209 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
2210 *step = 6;
2211 return (hi << 8) + lo;
2212 } else if (character == '%' &&
2213 i <= length - 3 &&
2214 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
2215 *step = 3;
2216 return lo;
2217 } else {
2218 *step = 1;
2219 return character;
2220 }
2221}
2222
2223
2224static Object* Runtime_URIUnescape(Arguments args) {
2225 NoHandleAllocation ha;
2226 ASSERT(args.length() == 1);
2227 CONVERT_CHECKED(String, source, args[0]);
2228
2229 source->TryFlatten();
2230
2231 bool ascii = true;
2232 int length = source->length();
2233
2234 int unescaped_length = 0;
2235 for (int i = 0; i < length; unescaped_length++) {
2236 int step;
2237 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
2238 ascii = false;
2239 i += step;
2240 }
2241
2242 // No length change implies no change. Return original string if no change.
2243 if (unescaped_length == length)
2244 return source;
2245
2246 Object* o = ascii ?
2247 Heap::AllocateRawAsciiString(unescaped_length) :
2248 Heap::AllocateRawTwoByteString(unescaped_length);
2249 if (o->IsFailure()) return o;
2250 String* destination = String::cast(o);
2251
2252 int dest_position = 0;
2253 for (int i = 0; i < length; dest_position++) {
2254 int step;
2255 destination->Set(dest_position, Unescape(source, i, length, &step));
2256 i += step;
2257 }
2258 return destination;
2259}
2260
2261
2262static Object* Runtime_StringParseInt(Arguments args) {
2263 NoHandleAllocation ha;
2264
2265 CONVERT_CHECKED(String, s, args[0]);
2266 CONVERT_DOUBLE_CHECKED(n, args[1]);
2267 int radix = FastD2I(n);
2268
2269 s->TryFlatten();
2270
2271 int len = s->length();
2272 int i;
2273
2274 // Skip leading white space.
2275 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
2276 if (i == len) return Heap::nan_value();
2277
2278 // Compute the sign (default to +).
2279 int sign = 1;
2280 if (s->Get(i) == '-') {
2281 sign = -1;
2282 i++;
2283 } else if (s->Get(i) == '+') {
2284 i++;
2285 }
2286
2287 // Compute the radix if 0.
2288 if (radix == 0) {
2289 radix = 10;
2290 if (i < len && s->Get(i) == '0') {
2291 radix = 8;
2292 if (i + 1 < len) {
2293 int c = s->Get(i + 1);
2294 if (c == 'x' || c == 'X') {
2295 radix = 16;
2296 i += 2;
2297 }
2298 }
2299 }
2300 } else if (radix == 16) {
2301 // Allow 0x or 0X prefix if radix is 16.
2302 if (i + 1 < len && s->Get(i) == '0') {
2303 int c = s->Get(i + 1);
2304 if (c == 'x' || c == 'X') i += 2;
2305 }
2306 }
2307
2308 RUNTIME_ASSERT(2 <= radix && radix <= 36);
2309 double value;
2310 int end_index = StringToInt(s, i, radix, &value);
2311 if (end_index != i) {
2312 return Heap::NumberFromDouble(sign * value);
2313 }
2314 return Heap::nan_value();
2315}
2316
2317
2318static Object* Runtime_StringParseFloat(Arguments args) {
2319 NoHandleAllocation ha;
2320 CONVERT_CHECKED(String, str, args[0]);
2321
2322 // ECMA-262 section 15.1.2.3, empty string is NaN
2323 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
2324
2325 // Create a number object from the value.
2326 return Heap::NumberFromDouble(value);
2327}
2328
2329
2330static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
2331static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
2332
2333
2334template <class Converter>
2335static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002336 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002337 NoHandleAllocation ha;
2338
2339 CONVERT_CHECKED(String, s, args[0]);
2340 int raw_string_length = s->length();
2341 // Assume that the string is not empty; we need this assumption later
2342 if (raw_string_length == 0) return s;
2343 int length = raw_string_length;
2344
2345 s->TryFlatten();
2346
2347 // We try this twice, once with the assumption that the result is
2348 // no longer than the input and, if that assumption breaks, again
2349 // with the exact length. This is implemented using a goto back
2350 // to this label if we discover that the assumption doesn't hold.
2351 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00002352 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002353 try_convert:
2354
2355 // Allocate the resulting string.
2356 //
2357 // NOTE: This assumes that the upper/lower case of an ascii
2358 // character is also ascii. This is currently the case, but it
2359 // might break in the future if we implement more context and locale
2360 // dependent upper/lower conversions.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002361 Object* o = s->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002362 ? Heap::AllocateRawAsciiString(length)
2363 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002364 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002365 String* result = String::cast(o);
2366 bool has_changed_character = false;
2367
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002368 // Convert all characters to upper case, assuming that they will fit
2369 // in the buffer
2370 Access<StringInputBuffer> buffer(&string_input_buffer);
2371 buffer->Reset(s);
2372 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
2373 int i = 0;
2374 // We can assume that the string is not empty
2375 uc32 current = buffer->GetNext();
2376 while (i < length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002377 bool has_next = buffer->has_more();
2378 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002379 int char_length = mapping->get(current, next, chars);
2380 if (char_length == 0) {
2381 // The case conversion of this character is the character itself.
2382 result->Set(i, current);
2383 i++;
2384 } else if (char_length == 1) {
2385 // Common case: converting the letter resulted in one character.
2386 ASSERT(static_cast<uc32>(chars[0]) != current);
2387 result->Set(i, chars[0]);
2388 has_changed_character = true;
2389 i++;
2390 } else if (length == raw_string_length) {
2391 // We've assumed that the result would be as long as the
2392 // input but here is a character that converts to several
2393 // characters. No matter, we calculate the exact length
2394 // of the result and try the whole thing again.
2395 //
2396 // Note that this leaves room for optimization. We could just
2397 // memcpy what we already have to the result string. Also,
2398 // the result string is the last object allocated we could
2399 // "realloc" it and probably, in the vast majority of cases,
2400 // extend the existing string to be able to hold the full
2401 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002402 int next_length = 0;
2403 if (has_next) {
2404 next_length = mapping->get(next, 0, chars);
2405 if (next_length == 0) next_length = 1;
2406 }
2407 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002408 while (buffer->has_more()) {
2409 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002410 // NOTE: we use 0 as the next character here because, while
2411 // the next character may affect what a character converts to,
2412 // it does not in any case affect the length of what it convert
2413 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002414 int char_length = mapping->get(current, 0, chars);
2415 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002416 current_length += char_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002417 }
2418 length = current_length;
2419 goto try_convert;
2420 } else {
2421 for (int j = 0; j < char_length; j++) {
2422 result->Set(i, chars[j]);
2423 i++;
2424 }
2425 has_changed_character = true;
2426 }
2427 current = next;
2428 }
2429 if (has_changed_character) {
2430 return result;
2431 } else {
2432 // If we didn't actually change anything in doing the conversion
2433 // we simple return the result and let the converted string
2434 // become garbage; there is no reason to keep two identical strings
2435 // alive.
2436 return s;
2437 }
2438}
2439
2440
2441static Object* Runtime_StringToLowerCase(Arguments args) {
2442 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
2443}
2444
2445
2446static Object* Runtime_StringToUpperCase(Arguments args) {
2447 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
2448}
2449
2450
2451static Object* Runtime_ConsStringFst(Arguments args) {
2452 NoHandleAllocation ha;
2453
2454 CONVERT_CHECKED(ConsString, str, args[0]);
2455 return str->first();
2456}
2457
2458
2459static Object* Runtime_ConsStringSnd(Arguments args) {
2460 NoHandleAllocation ha;
2461
2462 CONVERT_CHECKED(ConsString, str, args[0]);
2463 return str->second();
2464}
2465
2466
2467static Object* Runtime_NumberToString(Arguments args) {
2468 NoHandleAllocation ha;
2469 ASSERT(args.length() == 1);
2470
2471 Object* number = args[0];
2472 RUNTIME_ASSERT(number->IsNumber());
2473
2474 Object* cached = Heap::GetNumberStringCache(number);
2475 if (cached != Heap::undefined_value()) {
2476 return cached;
2477 }
2478
2479 char arr[100];
2480 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2481 const char* str;
2482 if (number->IsSmi()) {
2483 int num = Smi::cast(number)->value();
2484 str = IntToCString(num, buffer);
2485 } else {
2486 double num = HeapNumber::cast(number)->value();
2487 str = DoubleToCString(num, buffer);
2488 }
2489 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2490
2491 if (!result->IsFailure()) {
2492 Heap::SetNumberStringCache(number, String::cast(result));
2493 }
2494 return result;
2495}
2496
2497
2498static Object* Runtime_NumberToInteger(Arguments args) {
2499 NoHandleAllocation ha;
2500 ASSERT(args.length() == 1);
2501
2502 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002503 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002504 CONVERT_DOUBLE_CHECKED(number, obj);
2505 return Heap::NumberFromDouble(DoubleToInteger(number));
2506}
2507
2508
2509static Object* Runtime_NumberToJSUint32(Arguments args) {
2510 NoHandleAllocation ha;
2511 ASSERT(args.length() == 1);
2512
2513 Object* obj = args[0];
2514 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2515 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2516 return Heap::NumberFromUint32(number);
2517}
2518
2519
2520static Object* Runtime_NumberToJSInt32(Arguments args) {
2521 NoHandleAllocation ha;
2522 ASSERT(args.length() == 1);
2523
2524 Object* obj = args[0];
2525 if (obj->IsSmi()) return obj;
2526 CONVERT_DOUBLE_CHECKED(number, obj);
2527 return Heap::NumberFromInt32(DoubleToInt32(number));
2528}
2529
2530
2531static Object* Runtime_NumberAdd(Arguments args) {
2532 NoHandleAllocation ha;
2533 ASSERT(args.length() == 2);
2534
2535 CONVERT_DOUBLE_CHECKED(x, args[0]);
2536 CONVERT_DOUBLE_CHECKED(y, args[1]);
2537 return Heap::AllocateHeapNumber(x + y);
2538}
2539
2540
2541static Object* Runtime_NumberSub(Arguments args) {
2542 NoHandleAllocation ha;
2543 ASSERT(args.length() == 2);
2544
2545 CONVERT_DOUBLE_CHECKED(x, args[0]);
2546 CONVERT_DOUBLE_CHECKED(y, args[1]);
2547 return Heap::AllocateHeapNumber(x - y);
2548}
2549
2550
2551static Object* Runtime_NumberMul(Arguments args) {
2552 NoHandleAllocation ha;
2553 ASSERT(args.length() == 2);
2554
2555 CONVERT_DOUBLE_CHECKED(x, args[0]);
2556 CONVERT_DOUBLE_CHECKED(y, args[1]);
2557 return Heap::AllocateHeapNumber(x * y);
2558}
2559
2560
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002561static Object* Runtime_NumberUnaryMinus(Arguments args) {
2562 NoHandleAllocation ha;
2563 ASSERT(args.length() == 1);
2564
2565 CONVERT_DOUBLE_CHECKED(x, args[0]);
2566 return Heap::AllocateHeapNumber(-x);
2567}
2568
2569
2570static Object* Runtime_NumberDiv(Arguments args) {
2571 NoHandleAllocation ha;
2572 ASSERT(args.length() == 2);
2573
2574 CONVERT_DOUBLE_CHECKED(x, args[0]);
2575 CONVERT_DOUBLE_CHECKED(y, args[1]);
2576 return Heap::NewNumberFromDouble(x / y);
2577}
2578
2579
2580static Object* Runtime_NumberMod(Arguments args) {
2581 NoHandleAllocation ha;
2582 ASSERT(args.length() == 2);
2583
2584 CONVERT_DOUBLE_CHECKED(x, args[0]);
2585 CONVERT_DOUBLE_CHECKED(y, args[1]);
2586
2587#ifdef WIN32
2588 // Workaround MS fmod bugs. ECMA-262 says:
2589 // dividend is finite and divisor is an infinity => result equals dividend
2590 // dividend is a zero and divisor is nonzero finite => result equals dividend
2591 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2592 !(x == 0 && (y != 0 && isfinite(y))))
2593#endif
2594 x = fmod(x, y);
2595 // NewNumberFromDouble may return a Smi instead of a Number object
2596 return Heap::NewNumberFromDouble(x);
2597}
2598
2599
2600static Object* Runtime_StringAdd(Arguments args) {
2601 NoHandleAllocation ha;
2602 ASSERT(args.length() == 2);
2603
2604 CONVERT_CHECKED(String, str1, args[0]);
2605 CONVERT_CHECKED(String, str2, args[1]);
2606 int len1 = str1->length();
2607 int len2 = str2->length();
2608 if (len1 == 0) return str2;
2609 if (len2 == 0) return str1;
2610 int length_sum = len1 + len2;
2611 // Make sure that an out of memory exception is thrown if the length
2612 // of the new cons string is too large to fit in a Smi.
2613 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2614 Top::context()->mark_out_of_memory();
2615 return Failure::OutOfMemoryException();
2616 }
2617 return Heap::AllocateConsString(str1, str2);
2618}
2619
2620
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002621template<typename sinkchar>
2622static inline void StringBuilderConcatHelper(String* special,
2623 sinkchar* sink,
2624 FixedArray* fixed_array,
2625 int array_length) {
2626 int position = 0;
2627 for (int i = 0; i < array_length; i++) {
2628 Object* element = fixed_array->get(i);
2629 if (element->IsSmi()) {
2630 int len = Smi::cast(element)->value();
2631 int pos = len >> 11;
2632 len &= 0x7ff;
2633 String::WriteToFlat(special, sink + position, pos, pos + len);
2634 position += len;
2635 } else {
2636 String* string = String::cast(element);
2637 int element_length = string->length();
2638 String::WriteToFlat(string, sink + position, 0, element_length);
2639 position += element_length;
2640 }
2641 }
2642}
2643
2644
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002645static Object* Runtime_StringBuilderConcat(Arguments args) {
2646 NoHandleAllocation ha;
2647 ASSERT(args.length() == 2);
2648 CONVERT_CHECKED(JSArray, array, args[0]);
2649 CONVERT_CHECKED(String, special, args[1]);
2650 int special_length = special->length();
2651 Object* smi_array_length = array->length();
2652 if (!smi_array_length->IsSmi()) {
2653 Top::context()->mark_out_of_memory();
2654 return Failure::OutOfMemoryException();
2655 }
2656 int array_length = Smi::cast(smi_array_length)->value();
2657 if (!array->HasFastElements()) {
2658 return Top::Throw(Heap::illegal_argument_symbol());
2659 }
2660 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002661 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002662 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002663 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002664
2665 if (array_length == 0) {
2666 return Heap::empty_string();
2667 } else if (array_length == 1) {
2668 Object* first = fixed_array->get(0);
2669 if (first->IsString()) return first;
2670 }
2671
ager@chromium.org7c537e22008-10-16 08:43:32 +00002672 bool ascii = special->IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673 int position = 0;
2674 for (int i = 0; i < array_length; i++) {
2675 Object* elt = fixed_array->get(i);
2676 if (elt->IsSmi()) {
2677 int len = Smi::cast(elt)->value();
2678 int pos = len >> 11;
2679 len &= 0x7ff;
2680 if (pos + len > special_length) {
2681 return Top::Throw(Heap::illegal_argument_symbol());
2682 }
2683 position += len;
2684 } else if (elt->IsString()) {
2685 String* element = String::cast(elt);
2686 int element_length = element->length();
2687 if (!Smi::IsValid(element_length + position)) {
2688 Top::context()->mark_out_of_memory();
2689 return Failure::OutOfMemoryException();
2690 }
2691 position += element_length;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002692 if (ascii && !element->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002693 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002695 } else {
2696 return Top::Throw(Heap::illegal_argument_symbol());
2697 }
2698 }
2699
2700 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002701 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002702
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 if (ascii) {
2704 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002705 if (object->IsFailure()) return object;
2706 SeqAsciiString* answer = SeqAsciiString::cast(object);
2707 StringBuilderConcatHelper(special,
2708 answer->GetChars(),
2709 fixed_array,
2710 array_length);
2711 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002712 } else {
2713 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002714 if (object->IsFailure()) return object;
2715 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
2716 StringBuilderConcatHelper(special,
2717 answer->GetChars(),
2718 fixed_array,
2719 array_length);
2720 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002721 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002722}
2723
2724
2725static Object* Runtime_NumberOr(Arguments args) {
2726 NoHandleAllocation ha;
2727 ASSERT(args.length() == 2);
2728
2729 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2730 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2731 return Heap::NumberFromInt32(x | y);
2732}
2733
2734
2735static Object* Runtime_NumberAnd(Arguments args) {
2736 NoHandleAllocation ha;
2737 ASSERT(args.length() == 2);
2738
2739 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2740 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2741 return Heap::NumberFromInt32(x & y);
2742}
2743
2744
2745static Object* Runtime_NumberXor(Arguments args) {
2746 NoHandleAllocation ha;
2747 ASSERT(args.length() == 2);
2748
2749 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2750 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2751 return Heap::NumberFromInt32(x ^ y);
2752}
2753
2754
2755static Object* Runtime_NumberNot(Arguments args) {
2756 NoHandleAllocation ha;
2757 ASSERT(args.length() == 1);
2758
2759 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2760 return Heap::NumberFromInt32(~x);
2761}
2762
2763
2764static Object* Runtime_NumberShl(Arguments args) {
2765 NoHandleAllocation ha;
2766 ASSERT(args.length() == 2);
2767
2768 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2769 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2770 return Heap::NumberFromInt32(x << (y & 0x1f));
2771}
2772
2773
2774static Object* Runtime_NumberShr(Arguments args) {
2775 NoHandleAllocation ha;
2776 ASSERT(args.length() == 2);
2777
2778 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2779 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2780 return Heap::NumberFromUint32(x >> (y & 0x1f));
2781}
2782
2783
2784static Object* Runtime_NumberSar(Arguments args) {
2785 NoHandleAllocation ha;
2786 ASSERT(args.length() == 2);
2787
2788 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2789 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2790 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2791}
2792
2793
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002794static Object* Runtime_NumberEquals(Arguments args) {
2795 NoHandleAllocation ha;
2796 ASSERT(args.length() == 2);
2797
2798 CONVERT_DOUBLE_CHECKED(x, args[0]);
2799 CONVERT_DOUBLE_CHECKED(y, args[1]);
2800 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
2801 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
2802 if (x == y) return Smi::FromInt(EQUAL);
2803 Object* result;
2804 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
2805 result = Smi::FromInt(EQUAL);
2806 } else {
2807 result = Smi::FromInt(NOT_EQUAL);
2808 }
2809 return result;
2810}
2811
2812
2813static Object* Runtime_StringEquals(Arguments args) {
2814 NoHandleAllocation ha;
2815 ASSERT(args.length() == 2);
2816
2817 CONVERT_CHECKED(String, x, args[0]);
2818 CONVERT_CHECKED(String, y, args[1]);
2819
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002820 bool not_equal = !x->Equals(y);
2821 // This is slightly convoluted because the value that signifies
2822 // equality is 0 and inequality is 1 so we have to negate the result
2823 // from String::Equals.
2824 ASSERT(not_equal == 0 || not_equal == 1);
2825 STATIC_CHECK(EQUAL == 0);
2826 STATIC_CHECK(NOT_EQUAL == 1);
2827 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002828}
2829
2830
2831static Object* Runtime_NumberCompare(Arguments args) {
2832 NoHandleAllocation ha;
2833 ASSERT(args.length() == 3);
2834
2835 CONVERT_DOUBLE_CHECKED(x, args[0]);
2836 CONVERT_DOUBLE_CHECKED(y, args[1]);
2837 if (isnan(x) || isnan(y)) return args[2];
2838 if (x == y) return Smi::FromInt(EQUAL);
2839 if (isless(x, y)) return Smi::FromInt(LESS);
2840 return Smi::FromInt(GREATER);
2841}
2842
2843
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002844// Compare two Smis as if they were converted to strings and then
2845// compared lexicographically.
2846static Object* Runtime_SmiLexicographicCompare(Arguments args) {
2847 NoHandleAllocation ha;
2848 ASSERT(args.length() == 2);
2849
2850 // Arrays for the individual characters of the two Smis. Smis are
2851 // 31 bit integers and 10 decimal digits are therefore enough.
2852 static int x_elms[10];
2853 static int y_elms[10];
2854
2855 // Extract the integer values from the Smis.
2856 CONVERT_CHECKED(Smi, x, args[0]);
2857 CONVERT_CHECKED(Smi, y, args[1]);
2858 int x_value = x->value();
2859 int y_value = y->value();
2860
2861 // If the integers are equal so are the string representations.
2862 if (x_value == y_value) return Smi::FromInt(EQUAL);
2863
2864 // If one of the integers are zero the normal integer order is the
2865 // same as the lexicographic order of the string representations.
2866 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
2867
2868 // If only one of the intergers is negative the negative number is
2869 // smallest because the char code of '-' is less than the char code
2870 // of any digit. Otherwise, we make both values positive.
2871 if (x_value < 0 || y_value < 0) {
2872 if (y_value >= 0) return Smi::FromInt(LESS);
2873 if (x_value >= 0) return Smi::FromInt(GREATER);
2874 x_value = -x_value;
2875 y_value = -y_value;
2876 }
2877
2878 // Convert the integers to arrays of their decimal digits.
2879 int x_index = 0;
2880 int y_index = 0;
2881 while (x_value > 0) {
2882 x_elms[x_index++] = x_value % 10;
2883 x_value /= 10;
2884 }
2885 while (y_value > 0) {
2886 y_elms[y_index++] = y_value % 10;
2887 y_value /= 10;
2888 }
2889
2890 // Loop through the arrays of decimal digits finding the first place
2891 // where they differ.
2892 while (--x_index >= 0 && --y_index >= 0) {
2893 int diff = x_elms[x_index] - y_elms[y_index];
2894 if (diff != 0) return Smi::FromInt(diff);
2895 }
2896
2897 // If one array is a suffix of the other array, the longest array is
2898 // the representation of the largest of the Smis in the
2899 // lexicographic ordering.
2900 return Smi::FromInt(x_index - y_index);
2901}
2902
2903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002904static Object* Runtime_StringCompare(Arguments args) {
2905 NoHandleAllocation ha;
2906 ASSERT(args.length() == 2);
2907
2908 CONVERT_CHECKED(String, x, args[0]);
2909 CONVERT_CHECKED(String, y, args[1]);
2910
2911 // A few fast case tests before we flatten.
2912 if (x == y) return Smi::FromInt(EQUAL);
2913 if (y->length() == 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002914 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002915 return Smi::FromInt(GREATER);
2916 } else if (x->length() == 0) {
2917 return Smi::FromInt(LESS);
2918 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002919
2920 int d = x->Get(0) - y->Get(0);
2921 if (d < 0) return Smi::FromInt(LESS);
2922 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002923
2924 x->TryFlatten();
2925 y->TryFlatten();
2926
2927 static StringInputBuffer bufx;
2928 static StringInputBuffer bufy;
2929 bufx.Reset(x);
2930 bufy.Reset(y);
2931 while (bufx.has_more() && bufy.has_more()) {
2932 int d = bufx.GetNext() - bufy.GetNext();
2933 if (d < 0) return Smi::FromInt(LESS);
2934 else if (d > 0) return Smi::FromInt(GREATER);
2935 }
2936
2937 // x is (non-trivial) prefix of y:
2938 if (bufy.has_more()) return Smi::FromInt(LESS);
2939 // y is prefix of x:
2940 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
2941}
2942
2943
2944static Object* Runtime_Math_abs(Arguments args) {
2945 NoHandleAllocation ha;
2946 ASSERT(args.length() == 1);
2947
2948 CONVERT_DOUBLE_CHECKED(x, args[0]);
2949 return Heap::AllocateHeapNumber(fabs(x));
2950}
2951
2952
2953static Object* Runtime_Math_acos(Arguments args) {
2954 NoHandleAllocation ha;
2955 ASSERT(args.length() == 1);
2956
2957 CONVERT_DOUBLE_CHECKED(x, args[0]);
2958 return Heap::AllocateHeapNumber(acos(x));
2959}
2960
2961
2962static Object* Runtime_Math_asin(Arguments args) {
2963 NoHandleAllocation ha;
2964 ASSERT(args.length() == 1);
2965
2966 CONVERT_DOUBLE_CHECKED(x, args[0]);
2967 return Heap::AllocateHeapNumber(asin(x));
2968}
2969
2970
2971static Object* Runtime_Math_atan(Arguments args) {
2972 NoHandleAllocation ha;
2973 ASSERT(args.length() == 1);
2974
2975 CONVERT_DOUBLE_CHECKED(x, args[0]);
2976 return Heap::AllocateHeapNumber(atan(x));
2977}
2978
2979
2980static Object* Runtime_Math_atan2(Arguments args) {
2981 NoHandleAllocation ha;
2982 ASSERT(args.length() == 2);
2983
2984 CONVERT_DOUBLE_CHECKED(x, args[0]);
2985 CONVERT_DOUBLE_CHECKED(y, args[1]);
2986 double result;
2987 if (isinf(x) && isinf(y)) {
2988 // Make sure that the result in case of two infinite arguments
2989 // is a multiple of Pi / 4. The sign of the result is determined
2990 // by the first argument (x) and the sign of the second argument
2991 // determines the multiplier: one or three.
2992 static double kPiDividedBy4 = 0.78539816339744830962;
2993 int multiplier = (x < 0) ? -1 : 1;
2994 if (y < 0) multiplier *= 3;
2995 result = multiplier * kPiDividedBy4;
2996 } else {
2997 result = atan2(x, y);
2998 }
2999 return Heap::AllocateHeapNumber(result);
3000}
3001
3002
3003static Object* Runtime_Math_ceil(Arguments args) {
3004 NoHandleAllocation ha;
3005 ASSERT(args.length() == 1);
3006
3007 CONVERT_DOUBLE_CHECKED(x, args[0]);
3008 return Heap::NumberFromDouble(ceiling(x));
3009}
3010
3011
3012static Object* Runtime_Math_cos(Arguments args) {
3013 NoHandleAllocation ha;
3014 ASSERT(args.length() == 1);
3015
3016 CONVERT_DOUBLE_CHECKED(x, args[0]);
3017 return Heap::AllocateHeapNumber(cos(x));
3018}
3019
3020
3021static Object* Runtime_Math_exp(Arguments args) {
3022 NoHandleAllocation ha;
3023 ASSERT(args.length() == 1);
3024
3025 CONVERT_DOUBLE_CHECKED(x, args[0]);
3026 return Heap::AllocateHeapNumber(exp(x));
3027}
3028
3029
3030static Object* Runtime_Math_floor(Arguments args) {
3031 NoHandleAllocation ha;
3032 ASSERT(args.length() == 1);
3033
3034 CONVERT_DOUBLE_CHECKED(x, args[0]);
3035 return Heap::NumberFromDouble(floor(x));
3036}
3037
3038
3039static Object* Runtime_Math_log(Arguments args) {
3040 NoHandleAllocation ha;
3041 ASSERT(args.length() == 1);
3042
3043 CONVERT_DOUBLE_CHECKED(x, args[0]);
3044 return Heap::AllocateHeapNumber(log(x));
3045}
3046
3047
3048static Object* Runtime_Math_pow(Arguments args) {
3049 NoHandleAllocation ha;
3050 ASSERT(args.length() == 2);
3051
3052 CONVERT_DOUBLE_CHECKED(x, args[0]);
3053 CONVERT_DOUBLE_CHECKED(y, args[1]);
3054 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
3055 return Heap::nan_value();
3056 } else if (y == 0) {
3057 return Smi::FromInt(1);
3058 } else {
3059 return Heap::AllocateHeapNumber(pow(x, y));
3060 }
3061}
3062
3063// Returns a number value with positive sign, greater than or equal to
3064// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00003065static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003066 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003067 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003068
3069 // To get much better precision, we combine the results of two
3070 // invocations of random(). The result is computed by normalizing a
3071 // double in the range [0, RAND_MAX + 1) obtained by adding the
3072 // high-order bits in the range [0, RAND_MAX] with the low-order
3073 // bits in the range [0, 1).
3074 double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
3075 double hi = static_cast<double>(random());
3076 double result = (hi + lo) / (RAND_MAX + 1.0);
3077 ASSERT(result >= 0 && result < 1);
3078 return Heap::AllocateHeapNumber(result);
3079}
3080
3081
3082static Object* Runtime_Math_round(Arguments args) {
3083 NoHandleAllocation ha;
3084 ASSERT(args.length() == 1);
3085
3086 CONVERT_DOUBLE_CHECKED(x, args[0]);
3087 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
3088 return Heap::NumberFromDouble(floor(x + 0.5));
3089}
3090
3091
3092static Object* Runtime_Math_sin(Arguments args) {
3093 NoHandleAllocation ha;
3094 ASSERT(args.length() == 1);
3095
3096 CONVERT_DOUBLE_CHECKED(x, args[0]);
3097 return Heap::AllocateHeapNumber(sin(x));
3098}
3099
3100
3101static Object* Runtime_Math_sqrt(Arguments args) {
3102 NoHandleAllocation ha;
3103 ASSERT(args.length() == 1);
3104
3105 CONVERT_DOUBLE_CHECKED(x, args[0]);
3106 return Heap::AllocateHeapNumber(sqrt(x));
3107}
3108
3109
3110static Object* Runtime_Math_tan(Arguments args) {
3111 NoHandleAllocation ha;
3112 ASSERT(args.length() == 1);
3113
3114 CONVERT_DOUBLE_CHECKED(x, args[0]);
3115 return Heap::AllocateHeapNumber(tan(x));
3116}
3117
3118
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003119// The NewArguments function is only used when constructing the
3120// arguments array when calling non-functions from JavaScript in
3121// runtime.js:CALL_NON_FUNCTION.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122static Object* Runtime_NewArguments(Arguments args) {
3123 NoHandleAllocation ha;
3124 ASSERT(args.length() == 1);
3125
3126 // ECMA-262, 3rd., 10.1.8, p.39
3127 CONVERT_CHECKED(JSFunction, callee, args[0]);
3128
3129 // Compute the frame holding the arguments.
3130 JavaScriptFrameIterator it;
3131 it.AdvanceToArgumentsFrame();
3132 JavaScriptFrame* frame = it.frame();
3133
3134 const int length = frame->GetProvidedParametersCount();
3135 Object* result = Heap::AllocateArgumentsObject(callee, length);
3136 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003137 if (length > 0) {
3138 Object* obj = Heap::AllocateFixedArray(length);
3139 if (obj->IsFailure()) return obj;
3140 FixedArray* array = FixedArray::cast(obj);
3141 ASSERT(array->length() == length);
3142 WriteBarrierMode mode = array->GetWriteBarrierMode();
3143 for (int i = 0; i < length; i++) {
3144 array->set(i, frame->GetParameter(i), mode);
3145 }
3146 JSObject::cast(result)->set_elements(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147 }
3148 return result;
3149}
3150
3151
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003152static Object* Runtime_NewArgumentsFast(Arguments args) {
3153 NoHandleAllocation ha;
3154 ASSERT(args.length() == 3);
3155
3156 JSFunction* callee = JSFunction::cast(args[0]);
3157 Object** parameters = reinterpret_cast<Object**>(args[1]);
3158 const int length = Smi::cast(args[2])->value();
3159
3160 Object* result = Heap::AllocateArgumentsObject(callee, length);
3161 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003162 ASSERT(Heap::InNewSpace(result));
3163
3164 // Allocate the elements if needed.
3165 if (length > 0) {
3166 // Allocate the fixed array.
3167 Object* obj = Heap::AllocateRawFixedArray(length);
3168 if (obj->IsFailure()) return obj;
3169 reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
3170 FixedArray* array = FixedArray::cast(obj);
3171 array->set_length(length);
3172 WriteBarrierMode mode = array->GetWriteBarrierMode();
3173 for (int i = 0; i < length; i++) {
3174 array->set(i, *--parameters, mode);
3175 }
3176 JSObject::cast(result)->set_elements(FixedArray::cast(obj),
3177 SKIP_WRITE_BARRIER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003178 }
3179 return result;
3180}
3181
3182
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003183static Object* Runtime_NewClosure(Arguments args) {
3184 HandleScope scope;
3185 ASSERT(args.length() == 2);
3186 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
3187 CONVERT_ARG_CHECKED(Context, context, 1);
3188
3189 Handle<JSFunction> result =
3190 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3191 return *result;
3192}
3193
3194
3195static Object* Runtime_NewObject(Arguments args) {
3196 NoHandleAllocation ha;
3197 ASSERT(args.length() == 1);
3198
3199 Object* constructor = args[0];
3200 if (constructor->IsJSFunction()) {
3201 JSFunction* function = JSFunction::cast(constructor);
3202
3203 // Handle steping into constructors.
3204 if (Debug::StepInActive()) {
3205 StackFrameIterator it;
3206 it.Advance();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003207 ASSERT(it.frame()->is_construct());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003208 it.Advance();
3209 if (it.frame()->fp() == Debug::step_in_fp()) {
3210 HandleScope scope;
3211 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
3212 }
3213 }
3214
3215 if (function->has_initial_map() &&
3216 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
3217 // The 'Function' function ignores the receiver object when
3218 // called using 'new' and creates a new JSFunction object that
3219 // is returned. The receiver object is only used for error
3220 // reporting if an error occurs when constructing the new
3221 // JSFunction. AllocateJSObject should not be used to allocate
3222 // JSFunctions since it does not properly initialize the shared
3223 // part of the function. Since the receiver is ignored anyway,
3224 // we use the global object as the receiver instead of a new
3225 // JSFunction object. This way, errors are reported the same
3226 // way whether or not 'Function' is called using 'new'.
3227 return Top::context()->global();
3228 }
3229 return Heap::AllocateJSObject(function);
3230 }
3231
3232 HandleScope scope;
3233 Handle<Object> cons(constructor);
3234 // The constructor is not a function; throw a type error.
3235 Handle<Object> type_error =
3236 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
3237 return Top::Throw(*type_error);
3238}
3239
3240
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003241static Object* Runtime_LazyCompile(Arguments args) {
3242 HandleScope scope;
3243 ASSERT(args.length() == 1);
3244
3245 Handle<JSFunction> function = args.at<JSFunction>(0);
3246#ifdef DEBUG
3247 if (FLAG_trace_lazy) {
3248 PrintF("[lazy: ");
3249 function->shared()->name()->Print();
3250 PrintF("]\n");
3251 }
3252#endif
3253
3254 // Compile the target function.
3255 ASSERT(!function->is_compiled());
3256 if (!CompileLazy(function, KEEP_EXCEPTION)) {
3257 return Failure::Exception();
3258 }
3259
3260 return function->code();
3261}
3262
3263
3264static Object* Runtime_GetCalledFunction(Arguments args) {
3265 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00003266 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003267 StackFrameIterator it;
3268 // Get past the JS-to-C exit frame.
3269 ASSERT(it.frame()->is_exit());
3270 it.Advance();
3271 // Get past the CALL_NON_FUNCTION activation frame.
3272 ASSERT(it.frame()->is_java_script());
3273 it.Advance();
3274 // Argument adaptor frames do not copy the function; we have to skip
3275 // past them to get to the real calling frame.
3276 if (it.frame()->is_arguments_adaptor()) it.Advance();
3277 // Get the function from the top of the expression stack of the
3278 // calling frame.
3279 StandardFrame* frame = StandardFrame::cast(it.frame());
3280 int index = frame->ComputeExpressionsCount() - 1;
3281 Object* result = frame->GetExpression(index);
3282 return result;
3283}
3284
3285
3286static Object* Runtime_GetFunctionDelegate(Arguments args) {
3287 HandleScope scope;
3288 ASSERT(args.length() == 1);
3289 RUNTIME_ASSERT(!args[0]->IsJSFunction());
3290 return *Execution::GetFunctionDelegate(args.at<Object>(0));
3291}
3292
3293
3294static Object* Runtime_NewContext(Arguments args) {
3295 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003296 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003297
kasper.lund7276f142008-07-30 08:49:36 +00003298 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003299 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
3300 Object* result = Heap::AllocateFunctionContext(length, function);
3301 if (result->IsFailure()) return result;
3302
3303 Top::set_context(Context::cast(result));
3304
kasper.lund7276f142008-07-30 08:49:36 +00003305 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003306}
3307
3308
3309static Object* Runtime_PushContext(Arguments args) {
3310 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003311 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003312
3313 // Convert the object to a proper JavaScript object.
kasper.lund7276f142008-07-30 08:49:36 +00003314 Object* object = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003315 if (!object->IsJSObject()) {
3316 object = object->ToObject();
3317 if (object->IsFailure()) {
3318 if (!Failure::cast(object)->IsInternalError()) return object;
3319 HandleScope scope;
kasper.lund7276f142008-07-30 08:49:36 +00003320 Handle<Object> handle(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003321 Handle<Object> result =
3322 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
3323 return Top::Throw(*result);
3324 }
3325 }
3326
3327 Object* result =
3328 Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
3329 if (result->IsFailure()) return result;
3330
3331 Top::set_context(Context::cast(result));
3332
kasper.lund7276f142008-07-30 08:49:36 +00003333 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003334}
3335
3336
3337static Object* Runtime_LookupContext(Arguments args) {
3338 HandleScope scope;
3339 ASSERT(args.length() == 2);
3340
3341 CONVERT_ARG_CHECKED(Context, context, 0);
3342 CONVERT_ARG_CHECKED(String, name, 1);
3343
3344 int index;
3345 PropertyAttributes attributes;
3346 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003347 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 context->Lookup(name, flags, &index, &attributes);
3349
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003350 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003351 ASSERT(holder->IsJSObject());
3352 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 }
3354
3355 // No intermediate context found. Use global object by default.
3356 return Top::context()->global();
3357}
3358
3359
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003360// A mechanism to return pairs of Object*'s. This is somewhat
3361// compiler-dependent as it assumes that a 64-bit value (a long long)
3362// is returned via two registers (edx:eax on ia32). Both the ia32 and
3363// arm platform support this; it is mostly an issue of "coaxing" the
3364// compiler to do the right thing.
3365//
3366// TODO(1236026): This is a non-portable hack that should be removed.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003367typedef uint64_t ObjectPair;
3368static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003369 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003370 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003371}
3372
3373
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003374static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003375 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
3376 USE(attributes);
3377 return x->IsTheHole() ? Heap::undefined_value() : x;
3378}
3379
3380
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003381static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
3382 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003383 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003384 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003385 JSFunction* context_extension_function =
3386 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003387 // If the holder isn't a context extension object, we just return it
3388 // as the receiver. This allows arguments objects to be used as
3389 // receivers, but only if they are put in the context scope chain
3390 // explicitly via a with-statement.
3391 Object* constructor = holder->map()->constructor();
3392 if (constructor != context_extension_function) return holder;
3393 // Fall back to using the global object as the receiver if the
3394 // property turns out to be a local variable allocated in a context
3395 // extension object - introduced via eval.
3396 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003397}
3398
3399
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003400static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401 HandleScope scope;
3402 ASSERT(args.length() == 2);
3403
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003404 if (!args[0]->IsContext() || !args[1]->IsString()) {
3405 return MakePair(IllegalOperation(), NULL);
3406 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003407 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003408 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409
3410 int index;
3411 PropertyAttributes attributes;
3412 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003413 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003414 context->Lookup(name, flags, &index, &attributes);
3415
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003416 // If the index is non-negative, the slot has been found in a local
3417 // variable or a parameter. Read it from the context object or the
3418 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003420 // If the "property" we were looking for is a local variable or an
3421 // argument in a context, the receiver is the global object; see
3422 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
3423 JSObject* receiver = Top::context()->global()->global_receiver();
3424 Object* value = (holder->IsContext())
3425 ? Context::cast(*holder)->get(index)
3426 : JSObject::cast(*holder)->GetElement(index);
3427 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428 }
3429
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003430 // If the holder is found, we read the property from it.
3431 if (!holder.is_null() && holder->IsJSObject()) {
3432 JSObject* object = JSObject::cast(*holder);
3433 ASSERT(object->HasProperty(*name));
3434 JSObject* receiver = (object->IsGlobalObject())
3435 ? GlobalObject::cast(object)->global_receiver()
3436 : ComputeReceiverForNonGlobal(object);
3437 // No need to unhole the value here. This is taken care of by the
3438 // GetProperty function.
3439 Object* value = object->GetProperty(*name);
3440 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003441 }
3442
3443 if (throw_error) {
3444 // The property doesn't exist - throw exception.
3445 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003446 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003447 return MakePair(Top::Throw(*reference_error), NULL);
3448 } else {
3449 // The property doesn't exist - return undefined
3450 return MakePair(Heap::undefined_value(), Heap::undefined_value());
3451 }
3452}
3453
3454
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003455static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003456 return LoadContextSlotHelper(args, true);
3457}
3458
3459
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003460static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003461 return LoadContextSlotHelper(args, false);
3462}
3463
3464
3465static Object* Runtime_StoreContextSlot(Arguments args) {
3466 HandleScope scope;
3467 ASSERT(args.length() == 3);
3468
3469 Handle<Object> value(args[0]);
3470 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003471 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003472
3473 int index;
3474 PropertyAttributes attributes;
3475 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003476 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003477 context->Lookup(name, flags, &index, &attributes);
3478
3479 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003480 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003481 // Ignore if read_only variable.
3482 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003483 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003484 }
3485 } else {
3486 ASSERT((attributes & READ_ONLY) == 0);
3487 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003488 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003489 USE(result);
3490 ASSERT(!result->IsFailure());
3491 }
3492 return *value;
3493 }
3494
3495 // Slow case: The property is not in a FixedArray context.
3496 // It is either in an JSObject extension context or it was not found.
3497 Handle<JSObject> context_ext;
3498
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003499 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003500 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003501 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003502 } else {
3503 // The property was not found. It needs to be stored in the global context.
3504 ASSERT(attributes == ABSENT);
3505 attributes = NONE;
3506 context_ext = Handle<JSObject>(Top::context()->global());
3507 }
3508
3509 // Set the property, but ignore if read_only variable.
3510 if ((attributes & READ_ONLY) == 0) {
3511 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
3512 if (set.is_null()) {
3513 // Failure::Exception is converted to a null handle in the
3514 // handle-based methods such as SetProperty. We therefore need
3515 // to convert null handles back to exceptions.
3516 ASSERT(Top::has_pending_exception());
3517 return Failure::Exception();
3518 }
3519 }
3520 return *value;
3521}
3522
3523
3524static Object* Runtime_Throw(Arguments args) {
3525 HandleScope scope;
3526 ASSERT(args.length() == 1);
3527
3528 return Top::Throw(args[0]);
3529}
3530
3531
3532static Object* Runtime_ReThrow(Arguments args) {
3533 HandleScope scope;
3534 ASSERT(args.length() == 1);
3535
3536 return Top::ReThrow(args[0]);
3537}
3538
3539
3540static Object* Runtime_ThrowReferenceError(Arguments args) {
3541 HandleScope scope;
3542 ASSERT(args.length() == 1);
3543
3544 Handle<Object> name(args[0]);
3545 Handle<Object> reference_error =
3546 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3547 return Top::Throw(*reference_error);
3548}
3549
3550
3551static Object* Runtime_StackOverflow(Arguments args) {
3552 NoHandleAllocation na;
3553 return Top::StackOverflow();
3554}
3555
3556
3557static Object* RuntimePreempt(Arguments args) {
3558 // Clear the preempt request flag.
3559 StackGuard::Continue(PREEMPT);
3560
3561 ContextSwitcher::PreemptionReceived();
3562
3563 {
3564 v8::Unlocker unlocker;
3565 Thread::YieldCPU();
3566 }
3567
3568 return Heap::undefined_value();
3569}
3570
3571
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003572static Object* DebugBreakHelper() {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003573 // Just continue if breaks are disabled.
3574 if (Debug::disable_break()) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003575 return Heap::undefined_value();
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003576 }
3577
kasper.lund7276f142008-07-30 08:49:36 +00003578 // Don't break in system functions. If the current function is
3579 // either in the builtins object of some context or is in the debug
3580 // context just return with the debug break stack guard active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003581 JavaScriptFrameIterator it;
3582 JavaScriptFrame* frame = it.frame();
3583 Object* fun = frame->function();
3584 if (fun->IsJSFunction()) {
3585 GlobalObject* global = JSFunction::cast(fun)->context()->global();
3586 if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003587 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003588 }
3589 }
3590
3591 // Clear the debug request flag.
3592 StackGuard::Continue(DEBUGBREAK);
3593
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594 HandleScope scope;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003595 // Enter the debugger. Just continue if we fail to enter the debugger.
3596 EnterDebugger debugger;
3597 if (debugger.FailedToEnter()) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003598 return Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003600
kasper.lund7276f142008-07-30 08:49:36 +00003601 // Notify the debug event listeners.
3602 Debugger::OnDebugBreak(Factory::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003603
3604 // Return to continue execution.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003605 return Heap::undefined_value();
3606}
3607
3608
3609static Object* Runtime_DebugBreak(Arguments args) {
3610 ASSERT(args.length() == 0);
3611 return DebugBreakHelper();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612}
3613
3614
3615static Object* Runtime_StackGuard(Arguments args) {
3616 ASSERT(args.length() == 1);
3617
3618 // First check if this is a real stack overflow.
3619 if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
3620
3621 // If not real stack overflow the stack guard was used to interrupt
3622 // execution for another purpose.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003623 if (StackGuard::IsDebugBreak()) DebugBreakHelper();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003624 if (StackGuard::IsPreempted()) RuntimePreempt(args);
3625 if (StackGuard::IsInterrupted()) {
3626 // interrupt
3627 StackGuard::Continue(INTERRUPT);
3628 return Top::StackOverflow();
3629 }
3630 return Heap::undefined_value();
3631}
3632
3633
3634// NOTE: These PrintXXX functions are defined for all builds (not just
3635// DEBUG builds) because we may want to be able to trace function
3636// calls in all modes.
3637static void PrintString(String* str) {
3638 // not uncommon to have empty strings
3639 if (str->length() > 0) {
3640 SmartPointer<char> s =
3641 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3642 PrintF("%s", *s);
3643 }
3644}
3645
3646
3647static void PrintObject(Object* obj) {
3648 if (obj->IsSmi()) {
3649 PrintF("%d", Smi::cast(obj)->value());
3650 } else if (obj->IsString() || obj->IsSymbol()) {
3651 PrintString(String::cast(obj));
3652 } else if (obj->IsNumber()) {
3653 PrintF("%g", obj->Number());
3654 } else if (obj->IsFailure()) {
3655 PrintF("<failure>");
3656 } else if (obj->IsUndefined()) {
3657 PrintF("<undefined>");
3658 } else if (obj->IsNull()) {
3659 PrintF("<null>");
3660 } else if (obj->IsTrue()) {
3661 PrintF("<true>");
3662 } else if (obj->IsFalse()) {
3663 PrintF("<false>");
3664 } else {
3665 PrintF("%p", obj);
3666 }
3667}
3668
3669
3670static int StackSize() {
3671 int n = 0;
3672 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3673 return n;
3674}
3675
3676
3677static void PrintTransition(Object* result) {
3678 // indentation
3679 { const int nmax = 80;
3680 int n = StackSize();
3681 if (n <= nmax)
3682 PrintF("%4d:%*s", n, n, "");
3683 else
3684 PrintF("%4d:%*s", n, nmax, "...");
3685 }
3686
3687 if (result == NULL) {
3688 // constructor calls
3689 JavaScriptFrameIterator it;
3690 JavaScriptFrame* frame = it.frame();
3691 if (frame->IsConstructor()) PrintF("new ");
3692 // function name
3693 Object* fun = frame->function();
3694 if (fun->IsJSFunction()) {
3695 PrintObject(JSFunction::cast(fun)->shared()->name());
3696 } else {
3697 PrintObject(fun);
3698 }
3699 // function arguments
3700 // (we are intentionally only printing the actually
3701 // supplied parameters, not all parameters required)
3702 PrintF("(this=");
3703 PrintObject(frame->receiver());
3704 const int length = frame->GetProvidedParametersCount();
3705 for (int i = 0; i < length; i++) {
3706 PrintF(", ");
3707 PrintObject(frame->GetParameter(i));
3708 }
3709 PrintF(") {\n");
3710
3711 } else {
3712 // function result
3713 PrintF("} -> ");
3714 PrintObject(result);
3715 PrintF("\n");
3716 }
3717}
3718
3719
3720static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003721 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003722 NoHandleAllocation ha;
3723 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003724 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003725}
3726
3727
3728static Object* Runtime_TraceExit(Arguments args) {
3729 NoHandleAllocation ha;
3730 PrintTransition(args[0]);
3731 return args[0]; // return TOS
3732}
3733
3734
3735static Object* Runtime_DebugPrint(Arguments args) {
3736 NoHandleAllocation ha;
3737 ASSERT(args.length() == 1);
3738
3739#ifdef DEBUG
3740 if (args[0]->IsString()) {
3741 // If we have a string, assume it's a code "marker"
3742 // and print some interesting cpu debugging info.
3743 JavaScriptFrameIterator it;
3744 JavaScriptFrame* frame = it.frame();
3745 PrintF("fp = %p, sp = %p, pp = %p: ",
3746 frame->fp(), frame->sp(), frame->pp());
3747 } else {
3748 PrintF("DebugPrint: ");
3749 }
3750 args[0]->Print();
3751#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003752 // ShortPrint is available in release mode. Print is not.
3753 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003754#endif
3755 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00003756 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003757
3758 return args[0]; // return TOS
3759}
3760
3761
3762static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003763 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 NoHandleAllocation ha;
3765 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003766 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767}
3768
3769
mads.s.ager31e71382008-08-13 09:32:07 +00003770static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003772 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773
3774 // According to ECMA-262, section 15.9.1, page 117, the precision of
3775 // the number in a Date object representing a particular instant in
3776 // time is milliseconds. Therefore, we floor the result of getting
3777 // the OS time.
3778 double millis = floor(OS::TimeCurrentMillis());
3779 return Heap::NumberFromDouble(millis);
3780}
3781
3782
3783static Object* Runtime_DateParseString(Arguments args) {
3784 HandleScope scope;
3785 ASSERT(args.length() == 1);
3786
3787 CONVERT_CHECKED(String, string_object, args[0]);
3788
3789 Handle<String> str(string_object);
3790 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3791 if (DateParser::Parse(*str, *output)) {
3792 return *Factory::NewJSArrayWithElements(output);
3793 } else {
3794 return *Factory::null_value();
3795 }
3796}
3797
3798
3799static Object* Runtime_DateLocalTimezone(Arguments args) {
3800 NoHandleAllocation ha;
3801 ASSERT(args.length() == 1);
3802
3803 CONVERT_DOUBLE_CHECKED(x, args[0]);
3804 char* zone = OS::LocalTimezone(x);
3805 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3806}
3807
3808
3809static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3810 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003811 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812
3813 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3814}
3815
3816
3817static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3818 NoHandleAllocation ha;
3819 ASSERT(args.length() == 1);
3820
3821 CONVERT_DOUBLE_CHECKED(x, args[0]);
3822 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3823}
3824
3825
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003826static Object* Runtime_NumberIsFinite(Arguments args) {
3827 NoHandleAllocation ha;
3828 ASSERT(args.length() == 1);
3829
3830 CONVERT_DOUBLE_CHECKED(value, args[0]);
3831 Object* result;
3832 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3833 result = Heap::false_value();
3834 } else {
3835 result = Heap::true_value();
3836 }
3837 return result;
3838}
3839
3840
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003841static Object* EvalContext() {
3842 // The topmost JS frame belongs to the eval function which called
3843 // the CompileString runtime function. We need to unwind one level
3844 // to get to the caller of eval.
3845 StackFrameLocator locator;
3846 JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
3847
kasper.lund44510672008-07-25 07:37:58 +00003848 // TODO(900055): Right now we check if the caller of eval() supports
3849 // eval to determine if it's an aliased eval or not. This may not be
3850 // entirely correct in the unlikely case where a function uses both
3851 // aliased and direct eval calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003852 HandleScope scope;
3853 if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
kasper.lund44510672008-07-25 07:37:58 +00003854 // Aliased eval: Evaluate in the global context of the eval
3855 // function to support aliased, cross environment evals.
3856 return *Top::global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003857 }
3858
3859 // Fetch the caller context from the frame.
3860 Handle<Context> caller(Context::cast(frame->context()));
3861
3862 // Check for eval() invocations that cross environments. Use the
3863 // context from the stack if evaluating in current environment.
3864 Handle<Context> target = Top::global_context();
3865 if (caller->global_context() == *target) return *caller;
3866
3867 // Compute a function closure that captures the calling context. We
3868 // need a function that has trivial scope info, since it is only
3869 // used to hold the context chain together.
3870 Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
3871 Factory::undefined_value());
3872 closure->set_context(*caller);
3873
3874 // Create a new adaptor context that has the target environment as
3875 // the extension object. This enables the evaluated code to see both
3876 // the current context with locals and everything and to see global
3877 // variables declared in the target global object. Furthermore, any
3878 // properties introduced with 'var' will be added to the target
3879 // global object because it is the extension object.
3880 Handle<Context> adaptor =
3881 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
3882 adaptor->set_extension(target->global());
3883 return *adaptor;
3884}
3885
3886
3887static Object* Runtime_EvalReceiver(Arguments args) {
3888 StackFrameLocator locator;
3889 return locator.FindJavaScriptFrame(1)->receiver();
3890}
3891
3892
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003893static Object* Runtime_GlobalReceiver(Arguments args) {
3894 ASSERT(args.length() == 1);
3895 Object* global = args[0];
3896 if (!global->IsJSGlobalObject()) return Heap::null_value();
3897 return JSGlobalObject::cast(global)->global_receiver();
3898}
3899
3900
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003901static Object* Runtime_CompileString(Arguments args) {
3902 HandleScope scope;
ager@chromium.org236ad962008-09-25 09:45:57 +00003903 ASSERT(args.length() == 3);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003904 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org236ad962008-09-25 09:45:57 +00003905 CONVERT_ARG_CHECKED(Smi, line_offset, 1);
3906 bool contextual = args[2]->IsTrue();
3907 RUNTIME_ASSERT(contextual || args[2]->IsFalse());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003908
3909 // Compute the eval context.
3910 Handle<Context> context;
3911 if (contextual) {
3912 // Get eval context. May not be available if we are calling eval
3913 // through an alias, and the corresponding frame doesn't have a
3914 // proper eval context set up.
3915 Object* eval_context = EvalContext();
3916 if (eval_context->IsFailure()) return eval_context;
3917 context = Handle<Context>(Context::cast(eval_context));
3918 } else {
3919 context = Handle<Context>(Top::context()->global_context());
3920 }
3921
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003922
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003923 // Compile source string.
3924 bool is_global = context->IsGlobalContext();
3925 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00003926 Compiler::CompileEval(source, line_offset->value(), is_global);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003927 if (boilerplate.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 Handle<JSFunction> fun =
3929 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3930 return *fun;
3931}
3932
3933
3934static Object* Runtime_CompileScript(Arguments args) {
3935 HandleScope scope;
3936 ASSERT(args.length() == 4);
3937
3938 CONVERT_ARG_CHECKED(String, source, 0);
3939 CONVERT_ARG_CHECKED(String, script, 1);
3940 CONVERT_CHECKED(Smi, line_attrs, args[2]);
3941 int line = line_attrs->value();
3942 CONVERT_CHECKED(Smi, col_attrs, args[3]);
3943 int col = col_attrs->value();
3944 Handle<JSFunction> boilerplate =
3945 Compiler::Compile(source, script, line, col, NULL, NULL);
3946 if (boilerplate.is_null()) return Failure::Exception();
3947 Handle<JSFunction> fun =
3948 Factory::NewFunctionFromBoilerplate(boilerplate,
3949 Handle<Context>(Top::context()));
3950 return *fun;
3951}
3952
3953
3954static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
3955 // This utility adjusts the property attributes for newly created Function
3956 // object ("new Function(...)") by changing the map.
3957 // All it does is changing the prototype property to enumerable
3958 // as specified in ECMA262, 15.3.5.2.
3959 HandleScope scope;
3960 ASSERT(args.length() == 1);
3961 CONVERT_ARG_CHECKED(JSFunction, func, 0);
3962 ASSERT(func->map()->instance_type() ==
3963 Top::function_instance_map()->instance_type());
3964 ASSERT(func->map()->instance_size() ==
3965 Top::function_instance_map()->instance_size());
3966 func->set_map(*Top::function_instance_map());
3967 return *func;
3968}
3969
3970
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003971// Push an array unto an array of arrays if it is not already in the
3972// array. Returns true if the element was pushed on the stack and
3973// false otherwise.
3974static Object* Runtime_PushIfAbsent(Arguments args) {
3975 ASSERT(args.length() == 2);
3976 CONVERT_CHECKED(JSArray, array, args[0]);
3977 CONVERT_CHECKED(JSArray, element, args[1]);
3978 RUNTIME_ASSERT(array->HasFastElements());
3979 int length = Smi::cast(array->length())->value();
3980 FixedArray* elements = FixedArray::cast(array->elements());
3981 for (int i = 0; i < length; i++) {
3982 if (elements->get(i) == element) return Heap::false_value();
3983 }
3984 Object* obj = array->SetFastElement(length, element);
3985 if (obj->IsFailure()) return obj;
3986 return Heap::true_value();
3987}
3988
3989
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990// This will not allocate (flatten the string), but it may run
3991// very slowly for very deeply nested ConsStrings. For debugging use only.
3992static Object* Runtime_GlobalPrint(Arguments args) {
3993 NoHandleAllocation ha;
3994 ASSERT(args.length() == 1);
3995
3996 CONVERT_CHECKED(String, string, args[0]);
3997 StringInputBuffer buffer(string);
3998 while (buffer.has_more()) {
3999 uint16_t character = buffer.GetNext();
4000 PrintF("%c", character);
4001 }
4002 return string;
4003}
4004
4005
4006static Object* Runtime_RemoveArrayHoles(Arguments args) {
4007 ASSERT(args.length() == 1);
4008 // Ignore the case if this is not a JSArray.
4009 if (!args[0]->IsJSArray()) return args[0];
4010 return JSArray::cast(args[0])->RemoveHoles();
4011}
4012
4013
4014// Move contents of argument 0 (an array) to argument 1 (an array)
4015static Object* Runtime_MoveArrayContents(Arguments args) {
4016 ASSERT(args.length() == 2);
4017 CONVERT_CHECKED(JSArray, from, args[0]);
4018 CONVERT_CHECKED(JSArray, to, args[1]);
4019 to->SetContent(FixedArray::cast(from->elements()));
4020 to->set_length(from->length());
4021 from->SetContent(Heap::empty_fixed_array());
4022 from->set_length(0);
4023 return to;
4024}
4025
4026
4027// How many elements does this array have?
4028static Object* Runtime_EstimateNumberOfElements(Arguments args) {
4029 ASSERT(args.length() == 1);
4030 CONVERT_CHECKED(JSArray, array, args[0]);
4031 HeapObject* elements = array->elements();
4032 if (elements->IsDictionary()) {
4033 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
4034 } else {
4035 return array->length();
4036 }
4037}
4038
4039
4040// Returns an array that tells you where in the [0, length) interval an array
4041// might have elements. Can either return keys or intervals. Keys can have
4042// gaps in (undefined). Intervals can also span over some undefined keys.
4043static Object* Runtime_GetArrayKeys(Arguments args) {
4044 ASSERT(args.length() == 2);
4045 HandleScope scope;
4046 CONVERT_CHECKED(JSArray, raw_array, args[0]);
4047 Handle<JSArray> array(raw_array);
4048 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004049 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 // Create an array and get all the keys into it, then remove all the
4051 // keys that are not integers in the range 0 to length-1.
4052 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
4053 int keys_length = keys->length();
4054 for (int i = 0; i < keys_length; i++) {
4055 Object* key = keys->get(i);
4056 uint32_t index;
4057 if (!Array::IndexFromObject(key, &index) || index >= length) {
4058 // Zap invalid keys.
4059 keys->set_undefined(i);
4060 }
4061 }
4062 return *Factory::NewJSArrayWithElements(keys);
4063 } else {
4064 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
4065 // -1 means start of array.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004066 single_interval->set(0,
4067 Smi::FromInt(-1),
4068 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 Handle<Object> length_object =
4070 Factory::NewNumber(static_cast<double>(length));
4071 single_interval->set(1, *length_object);
4072 return *Factory::NewJSArrayWithElements(single_interval);
4073 }
4074}
4075
4076
4077// DefineAccessor takes an optional final argument which is the
4078// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
4079// to the way accessors are implemented, it is set for both the getter
4080// and setter on the first call to DefineAccessor and ignored on
4081// subsequent calls.
4082static Object* Runtime_DefineAccessor(Arguments args) {
4083 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
4084 // Compute attributes.
4085 PropertyAttributes attributes = NONE;
4086 if (args.length() == 5) {
4087 CONVERT_CHECKED(Smi, attrs, args[4]);
4088 int value = attrs->value();
4089 // Only attribute bits should be set.
4090 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4091 attributes = static_cast<PropertyAttributes>(value);
4092 }
4093
4094 CONVERT_CHECKED(JSObject, obj, args[0]);
4095 CONVERT_CHECKED(String, name, args[1]);
4096 CONVERT_CHECKED(Smi, flag, args[2]);
4097 CONVERT_CHECKED(JSFunction, fun, args[3]);
4098 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
4099}
4100
4101
4102static Object* Runtime_LookupAccessor(Arguments args) {
4103 ASSERT(args.length() == 3);
4104 CONVERT_CHECKED(JSObject, obj, args[0]);
4105 CONVERT_CHECKED(String, name, args[1]);
4106 CONVERT_CHECKED(Smi, flag, args[2]);
4107 return obj->LookupAccessor(name, flag->value() == 0);
4108}
4109
4110
4111// Helper functions for wrapping and unwrapping stack frame ids.
4112static Smi* WrapFrameId(StackFrame::Id id) {
4113 ASSERT(IsAligned(OffsetFrom(id), 4));
4114 return Smi::FromInt(id >> 2);
4115}
4116
4117
4118static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
4119 return static_cast<StackFrame::Id>(wrapped->value() << 2);
4120}
4121
4122
4123// Adds a JavaScript function as a debug event listener.
4124// args[0]: debug event listener function
4125// args[1]: object supplied during callback
4126static Object* Runtime_AddDebugEventListener(Arguments args) {
4127 ASSERT(args.length() == 2);
4128 // Convert the parameters to API objects to call the API function for adding
4129 // a JavaScript function as debug event listener.
4130 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4131 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
4132 v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
4133 v8::Debug::AddDebugEventListener(fun, data);
4134
4135 return Heap::undefined_value();
4136}
4137
4138
4139// Removes a JavaScript function debug event listener.
4140// args[0]: debug event listener function
4141static Object* Runtime_RemoveDebugEventListener(Arguments args) {
4142 ASSERT(args.length() == 1);
4143 // Convert the parameter to an API object to call the API function for
4144 // removing a JavaScript function debug event listener.
4145 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4146 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
4147 v8::Debug::RemoveDebugEventListener(fun);
4148
4149 return Heap::undefined_value();
4150}
4151
4152
4153static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004154 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004155 StackGuard::DebugBreak();
4156 return Heap::undefined_value();
4157}
4158
4159
4160static Object* DebugLookupResultValue(LookupResult* result) {
4161 Object* value;
4162 switch (result->type()) {
4163 case NORMAL: {
4164 Dictionary* dict =
4165 JSObject::cast(result->holder())->property_dictionary();
4166 value = dict->ValueAt(result->GetDictionaryEntry());
4167 if (value->IsTheHole()) {
4168 return Heap::undefined_value();
4169 }
4170 return value;
4171 }
4172 case FIELD:
4173 value =
4174 JSObject::cast(
ager@chromium.org7c537e22008-10-16 08:43:32 +00004175 result->holder())->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004176 if (value->IsTheHole()) {
4177 return Heap::undefined_value();
4178 }
4179 return value;
4180 case CONSTANT_FUNCTION:
4181 return result->GetConstantFunction();
4182 case CALLBACKS:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004184 case MAP_TRANSITION:
4185 case CONSTANT_TRANSITION:
4186 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004187 return Heap::undefined_value();
4188 default:
4189 UNREACHABLE();
4190 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004191 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004192 return Heap::undefined_value();
4193}
4194
4195
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004196static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004197 HandleScope scope;
4198
4199 ASSERT(args.length() == 2);
4200
4201 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4202 CONVERT_ARG_CHECKED(String, name, 1);
4203
4204 // Check if the name is trivially convertible to an index and get the element
4205 // if so.
4206 uint32_t index;
4207 if (name->AsArrayIndex(&index)) {
4208 Handle<FixedArray> details = Factory::NewFixedArray(2);
4209 details->set(0, Runtime::GetElementOrCharAt(obj, index));
4210 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
4211 return *Factory::NewJSArrayWithElements(details);
4212 }
4213
4214 // Perform standard local lookup on the object.
4215 LookupResult result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004216 obj->Lookup(*name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004217 if (result.IsProperty()) {
4218 Handle<Object> value(DebugLookupResultValue(&result));
4219 Handle<FixedArray> details = Factory::NewFixedArray(2);
4220 details->set(0, *value);
4221 details->set(1, result.GetPropertyDetails().AsSmi());
4222 return *Factory::NewJSArrayWithElements(details);
4223 }
4224 return Heap::undefined_value();
4225}
4226
4227
4228static Object* Runtime_DebugGetProperty(Arguments args) {
4229 HandleScope scope;
4230
4231 ASSERT(args.length() == 2);
4232
4233 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4234 CONVERT_ARG_CHECKED(String, name, 1);
4235
4236 LookupResult result;
4237 obj->Lookup(*name, &result);
4238 if (result.IsProperty()) {
4239 return DebugLookupResultValue(&result);
4240 }
4241 return Heap::undefined_value();
4242}
4243
4244
4245// Return the names of the local named properties.
4246// args[0]: object
4247static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
4248 HandleScope scope;
4249 ASSERT(args.length() == 1);
4250 if (!args[0]->IsJSObject()) {
4251 return Heap::undefined_value();
4252 }
4253 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4254
4255 int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4256 Handle<FixedArray> names = Factory::NewFixedArray(n);
4257 obj->GetLocalPropertyNames(*names);
4258 return *Factory::NewJSArrayWithElements(names);
4259}
4260
4261
4262// Return the names of the local indexed properties.
4263// args[0]: object
4264static Object* Runtime_DebugLocalElementNames(Arguments args) {
4265 HandleScope scope;
4266 ASSERT(args.length() == 1);
4267 if (!args[0]->IsJSObject()) {
4268 return Heap::undefined_value();
4269 }
4270 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4271
4272 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4273 Handle<FixedArray> names = Factory::NewFixedArray(n);
4274 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4275 return *Factory::NewJSArrayWithElements(names);
4276}
4277
4278
4279// Return the property type calculated from the property details.
4280// args[0]: smi with property details.
4281static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
4282 ASSERT(args.length() == 1);
4283 CONVERT_CHECKED(Smi, details, args[0]);
4284 PropertyType type = PropertyDetails(details).type();
4285 return Smi::FromInt(static_cast<int>(type));
4286}
4287
4288
4289// Return the property attribute calculated from the property details.
4290// args[0]: smi with property details.
4291static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
4292 ASSERT(args.length() == 1);
4293 CONVERT_CHECKED(Smi, details, args[0]);
4294 PropertyAttributes attributes = PropertyDetails(details).attributes();
4295 return Smi::FromInt(static_cast<int>(attributes));
4296}
4297
4298
4299// Return the property insertion index calculated from the property details.
4300// args[0]: smi with property details.
4301static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
4302 ASSERT(args.length() == 1);
4303 CONVERT_CHECKED(Smi, details, args[0]);
4304 int index = PropertyDetails(details).index();
4305 return Smi::FromInt(index);
4306}
4307
4308
4309// Return information on whether an object has a named or indexed interceptor.
4310// args[0]: object
4311static Object* Runtime_DebugInterceptorInfo(Arguments args) {
4312 HandleScope scope;
4313 ASSERT(args.length() == 1);
4314 if (!args[0]->IsJSObject()) {
4315 return Smi::FromInt(0);
4316 }
4317 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4318
4319 int result = 0;
4320 if (obj->HasNamedInterceptor()) result |= 2;
4321 if (obj->HasIndexedInterceptor()) result |= 1;
4322
4323 return Smi::FromInt(result);
4324}
4325
4326
4327// Return property names from named interceptor.
4328// args[0]: object
4329static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
4330 HandleScope scope;
4331 ASSERT(args.length() == 1);
4332 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4333 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4334
4335 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4336 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4337 return Heap::undefined_value();
4338}
4339
4340
4341// Return element names from indexed interceptor.
4342// args[0]: object
4343static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
4344 HandleScope scope;
4345 ASSERT(args.length() == 1);
4346 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4347 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4348
4349 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4350 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4351 return Heap::undefined_value();
4352}
4353
4354
4355// Return property value from named interceptor.
4356// args[0]: object
4357// args[1]: property name
4358static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
4359 HandleScope scope;
4360 ASSERT(args.length() == 2);
4361 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4362 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4363 CONVERT_ARG_CHECKED(String, name, 1);
4364
4365 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004366 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004367}
4368
4369
4370// Return element value from indexed interceptor.
4371// args[0]: object
4372// args[1]: index
4373static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
4374 HandleScope scope;
4375 ASSERT(args.length() == 2);
4376 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4377 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4378 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
4379
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004380 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004381}
4382
4383
4384static Object* Runtime_CheckExecutionState(Arguments args) {
4385 ASSERT(args.length() >= 1);
4386 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
4387 // Check that the break id is valid and that there is a valid frame
4388 // where execution is broken.
4389 if (break_id != Top::break_id() ||
4390 Top::break_frame_id() == StackFrame::NO_ID) {
4391 return Top::Throw(Heap::illegal_execution_state_symbol());
4392 }
4393
4394 return Heap::true_value();
4395}
4396
4397
4398static Object* Runtime_GetFrameCount(Arguments args) {
4399 HandleScope scope;
4400 ASSERT(args.length() == 1);
4401
4402 // Check arguments.
4403 Object* result = Runtime_CheckExecutionState(args);
4404 if (result->IsFailure()) return result;
4405
4406 // Count all frames which are relevant to debugging stack trace.
4407 int n = 0;
4408 StackFrame::Id id = Top::break_frame_id();
4409 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
4410 return Smi::FromInt(n);
4411}
4412
4413
4414static const int kFrameDetailsFrameIdIndex = 0;
4415static const int kFrameDetailsReceiverIndex = 1;
4416static const int kFrameDetailsFunctionIndex = 2;
4417static const int kFrameDetailsArgumentCountIndex = 3;
4418static const int kFrameDetailsLocalCountIndex = 4;
4419static const int kFrameDetailsSourcePositionIndex = 5;
4420static const int kFrameDetailsConstructCallIndex = 6;
4421static const int kFrameDetailsDebuggerFrameIndex = 7;
4422static const int kFrameDetailsFirstDynamicIndex = 8;
4423
4424// Return an array with frame details
4425// args[0]: number: break id
4426// args[1]: number: frame index
4427//
4428// The array returned contains the following information:
4429// 0: Frame id
4430// 1: Receiver
4431// 2: Function
4432// 3: Argument count
4433// 4: Local count
4434// 5: Source position
4435// 6: Constructor call
4436// 7: Debugger frame
4437// Arguments name, value
4438// Locals name, value
4439static Object* Runtime_GetFrameDetails(Arguments args) {
4440 HandleScope scope;
4441 ASSERT(args.length() == 2);
4442
4443 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004444 Object* check = Runtime_CheckExecutionState(args);
4445 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
4447
4448 // Find the relevant frame with the requested index.
4449 StackFrame::Id id = Top::break_frame_id();
4450 int count = 0;
4451 JavaScriptFrameIterator it(id);
4452 for (; !it.done(); it.Advance()) {
4453 if (count == index) break;
4454 count++;
4455 }
4456 if (it.done()) return Heap::undefined_value();
4457
4458 // Traverse the saved contexts chain to find the active context for the
4459 // selected frame.
4460 SaveContext* save = Top::save_context();
4461 while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
4462 save = save->prev();
4463 }
4464
4465 // Get the frame id.
4466 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
4467
4468 // Find source position.
4469 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
4470
4471 // Check for constructor frame.
4472 bool constructor = it.frame()->IsConstructor();
4473
4474 // Get code and read scope info from it for local variable information.
4475 Handle<Code> code(it.frame()->FindCode());
4476 ScopeInfo<> info(*code);
4477
4478 // Get the context.
4479 Handle<Context> context(Context::cast(it.frame()->context()));
4480
4481 // Get the locals names and values into a temporary array.
4482 //
4483 // TODO(1240907): Hide compiler-introduced stack variables
4484 // (e.g. .result)? For users of the debugger, they will probably be
4485 // confusing.
4486 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
4487 for (int i = 0; i < info.NumberOfLocals(); i++) {
4488 // Name of the local.
4489 locals->set(i * 2, *info.LocalName(i));
4490
4491 // Fetch the value of the local - either from the stack or from a
4492 // heap-allocated context.
4493 if (i < info.number_of_stack_slots()) {
4494 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
4495 } else {
4496 Handle<String> name = info.LocalName(i);
4497 // Traverse the context chain to the function context as all local
4498 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004499 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004500 context = Handle<Context>(context->previous());
4501 }
4502 ASSERT(context->is_function_context());
4503 locals->set(i * 2 + 1,
4504 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
4505 NULL)));
4506 }
4507 }
4508
4509 // Now advance to the arguments adapter frame (if any). If contains all
4510 // the provided parameters and
4511
4512 // Now advance to the arguments adapter frame (if any). It contains all
4513 // the provided parameters whereas the function frame always have the number
4514 // of arguments matching the functions parameters. The rest of the
4515 // information (except for what is collected above) is the same.
4516 it.AdvanceToArgumentsFrame();
4517
4518 // Find the number of arguments to fill. At least fill the number of
4519 // parameters for the function and fill more if more parameters are provided.
4520 int argument_count = info.number_of_parameters();
4521 if (argument_count < it.frame()->GetProvidedParametersCount()) {
4522 argument_count = it.frame()->GetProvidedParametersCount();
4523 }
4524
4525 // Calculate the size of the result.
4526 int details_size = kFrameDetailsFirstDynamicIndex +
4527 2 * (argument_count + info.NumberOfLocals());
4528 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
4529
4530 // Add the frame id.
4531 details->set(kFrameDetailsFrameIdIndex, *frame_id);
4532
4533 // Add the function (same as in function frame).
4534 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
4535
4536 // Add the arguments count.
4537 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
4538
4539 // Add the locals count
4540 details->set(kFrameDetailsLocalCountIndex,
4541 Smi::FromInt(info.NumberOfLocals()));
4542
4543 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00004544 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004545 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
4546 } else {
4547 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
4548 }
4549
4550 // Add the constructor information.
4551 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
4552
4553 // Add information on whether this frame is invoked in the debugger context.
4554 details->set(kFrameDetailsDebuggerFrameIndex,
4555 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
4556
4557 // Fill the dynamic part.
4558 int details_index = kFrameDetailsFirstDynamicIndex;
4559
4560 // Add arguments name and value.
4561 for (int i = 0; i < argument_count; i++) {
4562 // Name of the argument.
4563 if (i < info.number_of_parameters()) {
4564 details->set(details_index++, *info.parameter_name(i));
4565 } else {
4566 details->set(details_index++, Heap::undefined_value());
4567 }
4568
4569 // Parameter value.
4570 if (i < it.frame()->GetProvidedParametersCount()) {
4571 details->set(details_index++, it.frame()->GetParameter(i));
4572 } else {
4573 details->set(details_index++, Heap::undefined_value());
4574 }
4575 }
4576
4577 // Add locals name and value from the temporary copy from the function frame.
4578 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
4579 details->set(details_index++, locals->get(i));
4580 }
4581
4582 // Add the receiver (same as in function frame).
4583 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
4584 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
4585 Handle<Object> receiver(it.frame()->receiver());
4586 if (!receiver->IsJSObject()) {
4587 // If the receiver is NOT a JSObject we have hit an optimization
4588 // where a value object is not converted into a wrapped JS objects.
4589 // To hide this optimization from the debugger, we wrap the receiver
4590 // by creating correct wrapper object based on the calling frame's
4591 // global context.
4592 it.Advance();
4593 Handle<Context> calling_frames_global_context(
4594 Context::cast(Context::cast(it.frame()->context())->global_context()));
4595 receiver = Factory::ToObject(receiver, calling_frames_global_context);
4596 }
4597 details->set(kFrameDetailsReceiverIndex, *receiver);
4598
4599 ASSERT_EQ(details_size, details_index);
4600 return *Factory::NewJSArrayWithElements(details);
4601}
4602
4603
4604static Object* Runtime_GetCFrames(Arguments args) {
4605 HandleScope scope;
4606 ASSERT(args.length() == 1);
4607 Object* result = Runtime_CheckExecutionState(args);
4608 if (result->IsFailure()) return result;
4609
4610 static const int kMaxCFramesSize = 200;
4611 OS::StackFrame frames[kMaxCFramesSize];
4612 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
4613 if (frames_count == OS::kStackWalkError) {
4614 return Heap::undefined_value();
4615 }
4616
4617 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
4618 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
4619 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
4620 for (int i = 0; i < frames_count; i++) {
4621 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
4622 frame_value->SetProperty(
4623 *address_str,
4624 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
4625 NONE);
4626
4627 // Get the stack walk text for this frame.
4628 Handle<String> frame_text;
4629 if (strlen(frames[i].text) > 0) {
4630 Vector<const char> str(frames[i].text, strlen(frames[i].text));
4631 frame_text = Factory::NewStringFromAscii(str);
4632 }
4633
4634 if (!frame_text.is_null()) {
4635 frame_value->SetProperty(*text_str, *frame_text, NONE);
4636 }
4637
4638 frames_array->set(i, *frame_value);
4639 }
4640 return *Factory::NewJSArrayWithElements(frames_array);
4641}
4642
4643
4644static Object* Runtime_GetBreakLocations(Arguments args) {
4645 HandleScope scope;
4646 ASSERT(args.length() == 1);
4647
4648 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4649 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4650 // Find the number of break points
4651 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
4652 if (break_locations->IsUndefined()) return Heap::undefined_value();
4653 // Return array as JS array
4654 return *Factory::NewJSArrayWithElements(
4655 Handle<FixedArray>::cast(break_locations));
4656}
4657
4658
4659// Set a break point in a function
4660// args[0]: function
4661// args[1]: number: break source position (within the function source)
4662// args[2]: number: break point object
4663static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
4664 HandleScope scope;
4665 ASSERT(args.length() == 3);
4666 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4667 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4668 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4669 RUNTIME_ASSERT(source_position >= 0);
4670 Handle<Object> break_point_object_arg = args.at<Object>(2);
4671
4672 // Set break point.
4673 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
4674
4675 return Heap::undefined_value();
4676}
4677
4678
4679static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
4680 int position) {
4681 // Iterate the heap looking for SharedFunctionInfo generated from the
4682 // script. The inner most SharedFunctionInfo containing the source position
4683 // for the requested break point is found.
4684 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
4685 // which is found is not compiled it is compiled and the heap is iterated
4686 // again as the compilation might create inner functions from the newly
4687 // compiled function and the actual requested break point might be in one of
4688 // these functions.
4689 bool done = false;
4690 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00004691 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004692 Handle<SharedFunctionInfo> target;
4693 // The current candidate for the last function in script:
4694 Handle<SharedFunctionInfo> last;
4695 while (!done) {
4696 HeapIterator iterator;
4697 while (iterator.has_next()) {
4698 HeapObject* obj = iterator.next();
4699 ASSERT(obj != NULL);
4700 if (obj->IsSharedFunctionInfo()) {
4701 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
4702 if (shared->script() == *script) {
4703 // If the SharedFunctionInfo found has the requested script data and
4704 // contains the source position it is a candidate.
4705 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00004706 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707 start_position = shared->start_position();
4708 }
4709 if (start_position <= position &&
4710 position <= shared->end_position()) {
4711 // If there is no candidate or this function is within the currrent
4712 // candidate this is the new candidate.
4713 if (target.is_null()) {
4714 target_start_position = start_position;
4715 target = shared;
4716 } else {
4717 if (target_start_position < start_position &&
4718 shared->end_position() < target->end_position()) {
4719 target_start_position = start_position;
4720 target = shared;
4721 }
4722 }
4723 }
4724
4725 // Keep track of the last function in the script.
4726 if (last.is_null() ||
4727 shared->end_position() > last->start_position()) {
4728 last = shared;
4729 }
4730 }
4731 }
4732 }
4733
4734 // Make sure some candidate is selected.
4735 if (target.is_null()) {
4736 if (!last.is_null()) {
4737 // Position after the last function - use last.
4738 target = last;
4739 } else {
4740 // Unable to find function - possibly script without any function.
4741 return Heap::undefined_value();
4742 }
4743 }
4744
4745 // If the candidate found is compiled we are done. NOTE: when lazy
4746 // compilation of inner functions is introduced some additional checking
4747 // needs to be done here to compile inner functions.
4748 done = target->is_compiled();
4749 if (!done) {
4750 // If the candidate is not compiled compile it to reveal any inner
4751 // functions which might contain the requested source position.
4752 CompileLazyShared(target, KEEP_EXCEPTION);
4753 }
4754 }
4755
4756 return *target;
4757}
4758
4759
4760// Change the state of a break point in a script. NOTE: Regarding performance
4761// see the NOTE for GetScriptFromScriptData.
4762// args[0]: script to set break point in
4763// args[1]: number: break source position (within the script source)
4764// args[2]: number: break point object
4765static Object* Runtime_SetScriptBreakPoint(Arguments args) {
4766 HandleScope scope;
4767 ASSERT(args.length() == 3);
4768 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
4769 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4770 RUNTIME_ASSERT(source_position >= 0);
4771 Handle<Object> break_point_object_arg = args.at<Object>(2);
4772
4773 // Get the script from the script wrapper.
4774 RUNTIME_ASSERT(wrapper->value()->IsScript());
4775 Handle<Script> script(Script::cast(wrapper->value()));
4776
4777 Object* result = FindSharedFunctionInfoInScript(script, source_position);
4778 if (!result->IsUndefined()) {
4779 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
4780 // Find position within function. The script position might be before the
4781 // source position of the first function.
4782 int position;
4783 if (shared->start_position() > source_position) {
4784 position = 0;
4785 } else {
4786 position = source_position - shared->start_position();
4787 }
4788 Debug::SetBreakPoint(shared, position, break_point_object_arg);
4789 }
4790 return Heap::undefined_value();
4791}
4792
4793
4794// Clear a break point
4795// args[0]: number: break point object
4796static Object* Runtime_ClearBreakPoint(Arguments args) {
4797 HandleScope scope;
4798 ASSERT(args.length() == 1);
4799 Handle<Object> break_point_object_arg = args.at<Object>(0);
4800
4801 // Clear break point.
4802 Debug::ClearBreakPoint(break_point_object_arg);
4803
4804 return Heap::undefined_value();
4805}
4806
4807
4808// Change the state of break on exceptions
4809// args[0]: boolean indicating uncaught exceptions
4810// args[1]: boolean indicating on/off
4811static Object* Runtime_ChangeBreakOnException(Arguments args) {
4812 HandleScope scope;
4813 ASSERT(args.length() == 2);
4814 ASSERT(args[0]->IsNumber());
4815 ASSERT(args[1]->IsBoolean());
4816
4817 // Update break point state
4818 ExceptionBreakType type =
4819 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
4820 bool enable = args[1]->ToBoolean()->IsTrue();
4821 Debug::ChangeBreakOnException(type, enable);
4822 return Heap::undefined_value();
4823}
4824
4825
4826// Prepare for stepping
4827// args[0]: break id for checking execution state
4828// args[1]: step action from the enumeration StepAction
4829// args[2]: number of times to perform the step
4830static Object* Runtime_PrepareStep(Arguments args) {
4831 HandleScope scope;
4832 ASSERT(args.length() == 3);
4833 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004834 Object* check = Runtime_CheckExecutionState(args);
4835 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
4837 return Top::Throw(Heap::illegal_argument_symbol());
4838 }
4839
4840 // Get the step action and check validity.
4841 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
4842 if (step_action != StepIn &&
4843 step_action != StepNext &&
4844 step_action != StepOut &&
4845 step_action != StepInMin &&
4846 step_action != StepMin) {
4847 return Top::Throw(Heap::illegal_argument_symbol());
4848 }
4849
4850 // Get the number of steps.
4851 int step_count = NumberToInt32(args[2]);
4852 if (step_count < 1) {
4853 return Top::Throw(Heap::illegal_argument_symbol());
4854 }
4855
4856 // Prepare step.
4857 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
4858 return Heap::undefined_value();
4859}
4860
4861
4862// Clear all stepping set by PrepareStep.
4863static Object* Runtime_ClearStepping(Arguments args) {
4864 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00004865 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004866 Debug::ClearStepping();
4867 return Heap::undefined_value();
4868}
4869
4870
4871// Creates a copy of the with context chain. The copy of the context chain is
4872// is linked to the function context supplied.
4873static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
4874 Handle<Context> function_context) {
4875 // At the bottom of the chain. Return the function context to link to.
4876 if (context_chain->is_function_context()) {
4877 return function_context;
4878 }
4879
4880 // Recursively copy the with contexts.
4881 Handle<Context> previous(context_chain->previous());
4882 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
4883 return Factory::NewWithContext(
4884 CopyWithContextChain(function_context, previous), extension);
4885}
4886
4887
4888// Helper function to find or create the arguments object for
4889// Runtime_DebugEvaluate.
4890static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
4891 Handle<JSFunction> function,
4892 Handle<Code> code,
4893 const ScopeInfo<>* sinfo,
4894 Handle<Context> function_context) {
4895 // Try to find the value of 'arguments' to pass as parameter. If it is not
4896 // found (that is the debugged function does not reference 'arguments' and
4897 // does not support eval) then create an 'arguments' object.
4898 int index;
4899 if (sinfo->number_of_stack_slots() > 0) {
4900 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
4901 if (index != -1) {
4902 return Handle<Object>(frame->GetExpression(index));
4903 }
4904 }
4905
4906 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
4907 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
4908 NULL);
4909 if (index != -1) {
4910 return Handle<Object>(function_context->get(index));
4911 }
4912 }
4913
4914 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004915 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
4916 Handle<FixedArray> array = Factory::NewFixedArray(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004917 WriteBarrierMode mode = array->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004918 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004919 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004921 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004922 return arguments;
4923}
4924
4925
4926// Evaluate a piece of JavaScript in the context of a stack frame for
4927// debugging. This is acomplished by creating a new context which in its
4928// extension part has all the parameters and locals of the function on the
4929// stack frame. A function which calls eval with the code to evaluate is then
4930// compiled in this context and called in this context. As this context
4931// replaces the context of the function on the stack frame a new (empty)
4932// function is created as well to be used as the closure for the context.
4933// This function and the context acts as replacements for the function on the
4934// stack frame presenting the same view of the values of parameters and
4935// local variables as if the piece of JavaScript was evaluated at the point
4936// where the function on the stack frame is currently stopped.
4937static Object* Runtime_DebugEvaluate(Arguments args) {
4938 HandleScope scope;
4939
4940 // Check the execution state and decode arguments frame and source to be
4941 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004942 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004943 Object* check_result = Runtime_CheckExecutionState(args);
4944 if (check_result->IsFailure()) return check_result;
4945 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
4946 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00004947 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
4948
4949 // Handle the processing of break.
4950 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004951
4952 // Get the frame where the debugging is performed.
4953 StackFrame::Id id = UnwrapFrameId(wrapped_id);
4954 JavaScriptFrameIterator it(id);
4955 JavaScriptFrame* frame = it.frame();
4956 Handle<JSFunction> function(JSFunction::cast(frame->function()));
4957 Handle<Code> code(function->code());
4958 ScopeInfo<> sinfo(*code);
4959
4960 // Traverse the saved contexts chain to find the active context for the
4961 // selected frame.
4962 SaveContext* save = Top::save_context();
4963 while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
4964 save = save->prev();
4965 }
4966 ASSERT(save != NULL);
4967 SaveContext savex;
4968 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004969
4970 // Create the (empty) function replacing the function on the stack frame for
4971 // the purpose of evaluating in the context created below. It is important
4972 // that this function does not describe any parameters and local variables
4973 // in the context. If it does then this will cause problems with the lookup
4974 // in Context::Lookup, where context slots for parameters and local variables
4975 // are looked at before the extension object.
4976 Handle<JSFunction> go_between =
4977 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
4978 go_between->set_context(function->context());
4979#ifdef DEBUG
4980 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
4981 ASSERT(go_between_sinfo.number_of_parameters() == 0);
4982 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
4983#endif
4984
4985 // Allocate and initialize a context extension object with all the
4986 // arguments, stack locals heap locals and extension properties of the
4987 // debugged function.
4988 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
4989 // First fill all parameters to the context extension.
4990 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
4991 SetProperty(context_ext,
4992 sinfo.parameter_name(i),
4993 Handle<Object>(frame->GetParameter(i)), NONE);
4994 }
4995 // Second fill all stack locals to the context extension.
4996 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
4997 SetProperty(context_ext,
4998 sinfo.stack_slot_name(i),
4999 Handle<Object>(frame->GetExpression(i)), NONE);
5000 }
5001 // Third fill all context locals to the context extension.
5002 Handle<Context> frame_context(Context::cast(frame->context()));
5003 Handle<Context> function_context(frame_context->fcontext());
5004 for (int i = Context::MIN_CONTEXT_SLOTS;
5005 i < sinfo.number_of_context_slots();
5006 ++i) {
5007 int context_index =
5008 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
5009 SetProperty(context_ext,
5010 sinfo.context_slot_name(i),
5011 Handle<Object>(function_context->get(context_index)), NONE);
5012 }
5013 // Finally copy any properties from the function context extension. This will
5014 // be variables introduced by eval.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005015 if (function_context->has_extension() &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016 !function_context->IsGlobalContext()) {
5017 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
5018 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
5019 for (int i = 0; i < keys->length(); i++) {
5020 // Names of variables introduced by eval are strings.
5021 ASSERT(keys->get(i)->IsString());
5022 Handle<String> key(String::cast(keys->get(i)));
5023 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
5024 }
5025 }
5026
5027 // Allocate a new context for the debug evaluation and set the extension
5028 // object build.
5029 Handle<Context> context =
5030 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
5031 context->set_extension(*context_ext);
5032 // Copy any with contexts present and chain them in front of this context.
5033 context = CopyWithContextChain(frame_context, context);
5034
5035 // Wrap the evaluation statement in a new function compiled in the newly
5036 // created context. The function has one parameter which has to be called
5037 // 'arguments'. This it to have access to what would have been 'arguments' in
5038 // the function beeing debugged.
5039 // function(arguments,__source__) {return eval(__source__);}
5040 static const char* source_str =
5041 "function(arguments,__source__){return eval(__source__);}";
5042 static const int source_str_length = strlen(source_str);
5043 Handle<String> function_source =
5044 Factory::NewStringFromAscii(Vector<const char>(source_str,
5045 source_str_length));
5046 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00005047 Compiler::CompileEval(function_source, 0, context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005048 if (boilerplate.is_null()) return Failure::Exception();
5049 Handle<JSFunction> compiled_function =
5050 Factory::NewFunctionFromBoilerplate(boilerplate, context);
5051
5052 // Invoke the result of the compilation to get the evaluation function.
5053 bool has_pending_exception;
5054 Handle<Object> receiver(frame->receiver());
5055 Handle<Object> evaluation_function =
5056 Execution::Call(compiled_function, receiver, 0, NULL,
5057 &has_pending_exception);
5058
5059 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
5060 function_context);
5061
5062 // Invoke the evaluation function and return the result.
5063 const int argc = 2;
5064 Object** argv[argc] = { arguments.location(),
5065 Handle<Object>::cast(source).location() };
5066 Handle<Object> result =
5067 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
5068 argc, argv, &has_pending_exception);
5069 return *result;
5070}
5071
5072
5073static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
5074 HandleScope scope;
5075
5076 // Check the execution state and decode arguments frame and source to be
5077 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005078 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005079 Object* check_result = Runtime_CheckExecutionState(args);
5080 if (check_result->IsFailure()) return check_result;
5081 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005082 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
5083
5084 // Handle the processing of break.
5085 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005086
5087 // Enter the top context from before the debugger was invoked.
5088 SaveContext save;
5089 SaveContext* top = &save;
5090 while (top != NULL && *top->context() == *Debug::debug_context()) {
5091 top = top->prev();
5092 }
5093 if (top != NULL) {
5094 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005095 }
5096
5097 // Get the global context now set to the top context from before the
5098 // debugger was invoked.
5099 Handle<Context> context = Top::global_context();
5100
5101 // Compile the source to be evaluated.
ager@chromium.org236ad962008-09-25 09:45:57 +00005102 Handle<JSFunction> boilerplate(Compiler::CompileEval(source, 0, true));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005103 if (boilerplate.is_null()) return Failure::Exception();
5104 Handle<JSFunction> compiled_function =
5105 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
5106 context));
5107
5108 // Invoke the result of the compilation to get the evaluation function.
5109 bool has_pending_exception;
5110 Handle<Object> receiver = Top::global();
5111 Handle<Object> result =
5112 Execution::Call(compiled_function, receiver, 0, NULL,
5113 &has_pending_exception);
5114 return *result;
5115}
5116
5117
5118// Helper function used by Runtime_DebugGetLoadedScripts below.
5119static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
5120 NoHandleAllocation ha;
5121 AssertNoAllocation no_alloc;
5122
5123 // Get hold of the current empty script.
5124 Context* context = Top::context()->global_context();
5125 Script* empty = context->empty_script();
5126
5127 // Scan heap for Script objects.
5128 int count = 0;
5129 HeapIterator iterator;
5130 while (iterator.has_next()) {
5131 HeapObject* obj = iterator.next();
5132 ASSERT(obj != NULL);
5133 if (obj->IsScript() && obj != empty) {
5134 if (instances != NULL && count < instances_size) {
5135 instances->set(count, obj);
5136 }
5137 count++;
5138 }
5139 }
5140
5141 return count;
5142}
5143
5144
5145static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
5146 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005147 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005148
5149 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
5150 // rid of all the cached script wrappes and the second gets rid of the
5151 // scripts which is no longer referenced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005152 Heap::CollectAllGarbage();
5153 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005154
5155 // Get the number of scripts.
5156 int count;
5157 count = DebugGetLoadedScripts(NULL, 0);
5158
5159 // Allocate an array to hold the result.
5160 Handle<FixedArray> instances = Factory::NewFixedArray(count);
5161
5162 // Fill the script objects.
5163 count = DebugGetLoadedScripts(*instances, count);
5164
5165 // Convert the script objects to proper JS objects.
5166 for (int i = 0; i < count; i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005167 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
5168 // Get the script wrapper in a local handle before calling GetScriptWrapper,
5169 // because using
5170 // instances->set(i, *GetScriptWrapper(script))
5171 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
5172 // already have deferenced the instances handle.
5173 Handle<JSValue> wrapper = GetScriptWrapper(script);
5174 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 }
5176
5177 // Return result as a JS array.
5178 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
5179 Handle<JSArray>::cast(result)->SetContent(*instances);
5180 return *result;
5181}
5182
5183
5184// Helper function used by Runtime_DebugReferencedBy below.
5185static int DebugReferencedBy(JSObject* target,
5186 Object* instance_filter, int max_references,
5187 FixedArray* instances, int instances_size,
5188 JSFunction* context_extension_function,
5189 JSFunction* arguments_function) {
5190 NoHandleAllocation ha;
5191 AssertNoAllocation no_alloc;
5192
5193 // Iterate the heap.
5194 int count = 0;
5195 JSObject* last = NULL;
5196 HeapIterator iterator;
5197 while (iterator.has_next() &&
5198 (max_references == 0 || count < max_references)) {
5199 // Only look at all JSObjects.
5200 HeapObject* heap_obj = iterator.next();
5201 if (heap_obj->IsJSObject()) {
5202 // Skip context extension objects and argument arrays as these are
5203 // checked in the context of functions using them.
5204 JSObject* obj = JSObject::cast(heap_obj);
5205 if (obj->map()->constructor() == context_extension_function ||
5206 obj->map()->constructor() == arguments_function) {
5207 continue;
5208 }
5209
5210 // Check if the JS object has a reference to the object looked for.
5211 if (obj->ReferencesObject(target)) {
5212 // Check instance filter if supplied. This is normally used to avoid
5213 // references from mirror objects (see Runtime_IsInPrototypeChain).
5214 if (!instance_filter->IsUndefined()) {
5215 Object* V = obj;
5216 while (true) {
5217 Object* prototype = V->GetPrototype();
5218 if (prototype->IsNull()) {
5219 break;
5220 }
5221 if (instance_filter == prototype) {
5222 obj = NULL; // Don't add this object.
5223 break;
5224 }
5225 V = prototype;
5226 }
5227 }
5228
5229 if (obj != NULL) {
5230 // Valid reference found add to instance array if supplied an update
5231 // count.
5232 if (instances != NULL && count < instances_size) {
5233 instances->set(count, obj);
5234 }
5235 last = obj;
5236 count++;
5237 }
5238 }
5239 }
5240 }
5241
5242 // Check for circular reference only. This can happen when the object is only
5243 // referenced from mirrors and has a circular reference in which case the
5244 // object is not really alive and would have been garbage collected if not
5245 // referenced from the mirror.
5246 if (count == 1 && last == target) {
5247 count = 0;
5248 }
5249
5250 // Return the number of referencing objects found.
5251 return count;
5252}
5253
5254
5255// Scan the heap for objects with direct references to an object
5256// args[0]: the object to find references to
5257// args[1]: constructor function for instances to exclude (Mirror)
5258// args[2]: the the maximum number of objects to return
5259static Object* Runtime_DebugReferencedBy(Arguments args) {
5260 ASSERT(args.length() == 3);
5261
5262 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005263 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005264
5265 // Check parameters.
5266 CONVERT_CHECKED(JSObject, target, args[0]);
5267 Object* instance_filter = args[1];
5268 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
5269 instance_filter->IsJSObject());
5270 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
5271 RUNTIME_ASSERT(max_references >= 0);
5272
5273 // Get the constructor function for context extension and arguments array.
5274 JSFunction* context_extension_function =
5275 Top::context()->global_context()->context_extension_function();
5276 JSObject* arguments_boilerplate =
5277 Top::context()->global_context()->arguments_boilerplate();
5278 JSFunction* arguments_function =
5279 JSFunction::cast(arguments_boilerplate->map()->constructor());
5280
5281 // Get the number of referencing objects.
5282 int count;
5283 count = DebugReferencedBy(target, instance_filter, max_references,
5284 NULL, 0,
5285 context_extension_function, arguments_function);
5286
5287 // Allocate an array to hold the result.
5288 Object* object = Heap::AllocateFixedArray(count);
5289 if (object->IsFailure()) return object;
5290 FixedArray* instances = FixedArray::cast(object);
5291
5292 // Fill the referencing objects.
5293 count = DebugReferencedBy(target, instance_filter, max_references,
5294 instances, count,
5295 context_extension_function, arguments_function);
5296
5297 // Return result as JS array.
5298 Object* result =
5299 Heap::AllocateJSObject(
5300 Top::context()->global_context()->array_function());
5301 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5302 return result;
5303}
5304
5305
5306// Helper function used by Runtime_DebugConstructedBy below.
5307static int DebugConstructedBy(JSFunction* constructor, int max_references,
5308 FixedArray* instances, int instances_size) {
5309 AssertNoAllocation no_alloc;
5310
5311 // Iterate the heap.
5312 int count = 0;
5313 HeapIterator iterator;
5314 while (iterator.has_next() &&
5315 (max_references == 0 || count < max_references)) {
5316 // Only look at all JSObjects.
5317 HeapObject* heap_obj = iterator.next();
5318 if (heap_obj->IsJSObject()) {
5319 JSObject* obj = JSObject::cast(heap_obj);
5320 if (obj->map()->constructor() == constructor) {
5321 // Valid reference found add to instance array if supplied an update
5322 // count.
5323 if (instances != NULL && count < instances_size) {
5324 instances->set(count, obj);
5325 }
5326 count++;
5327 }
5328 }
5329 }
5330
5331 // Return the number of referencing objects found.
5332 return count;
5333}
5334
5335
5336// Scan the heap for objects constructed by a specific function.
5337// args[0]: the constructor to find instances of
5338// args[1]: the the maximum number of objects to return
5339static Object* Runtime_DebugConstructedBy(Arguments args) {
5340 ASSERT(args.length() == 2);
5341
5342 // First perform a full GC in order to avoid dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005343 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005344
5345 // Check parameters.
5346 CONVERT_CHECKED(JSFunction, constructor, args[0]);
5347 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
5348 RUNTIME_ASSERT(max_references >= 0);
5349
5350 // Get the number of referencing objects.
5351 int count;
5352 count = DebugConstructedBy(constructor, max_references, NULL, 0);
5353
5354 // Allocate an array to hold the result.
5355 Object* object = Heap::AllocateFixedArray(count);
5356 if (object->IsFailure()) return object;
5357 FixedArray* instances = FixedArray::cast(object);
5358
5359 // Fill the referencing objects.
5360 count = DebugConstructedBy(constructor, max_references, instances, count);
5361
5362 // Return result as JS array.
5363 Object* result =
5364 Heap::AllocateJSObject(
5365 Top::context()->global_context()->array_function());
5366 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5367 return result;
5368}
5369
5370
5371static Object* Runtime_GetPrototype(Arguments args) {
5372 ASSERT(args.length() == 1);
5373
5374 CONVERT_CHECKED(JSObject, obj, args[0]);
5375
5376 return obj->GetPrototype();
5377}
5378
5379
5380static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005381 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382 CPU::DebugBreak();
5383 return Heap::undefined_value();
5384}
5385
5386
5387// Finds the script object from the script data. NOTE: This operation uses
5388// heap traversal to find the function generated for the source position
5389// for the requested break point. For lazily compiled functions several heap
5390// traversals might be required rendering this operation as a rather slow
5391// operation. However for setting break points which is normally done through
5392// some kind of user interaction the performance is not crucial.
5393static Handle<Object> Runtime_GetScriptFromScriptName(
5394 Handle<String> script_name) {
5395 // Scan the heap for Script objects to find the script with the requested
5396 // script data.
5397 Handle<Script> script;
5398 HeapIterator iterator;
5399 while (script.is_null() && iterator.has_next()) {
5400 HeapObject* obj = iterator.next();
5401 // If a script is found check if it has the script data requested.
5402 if (obj->IsScript()) {
5403 if (Script::cast(obj)->name()->IsString()) {
5404 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
5405 script = Handle<Script>(Script::cast(obj));
5406 }
5407 }
5408 }
5409 }
5410
5411 // If no script with the requested script data is found return undefined.
5412 if (script.is_null()) return Factory::undefined_value();
5413
5414 // Return the script found.
5415 return GetScriptWrapper(script);
5416}
5417
5418
5419// Get the script object from script data. NOTE: Regarding performance
5420// see the NOTE for GetScriptFromScriptData.
5421// args[0]: script data for the script to find the source for
5422static Object* Runtime_GetScript(Arguments args) {
5423 HandleScope scope;
5424
5425 ASSERT(args.length() == 1);
5426
5427 CONVERT_CHECKED(String, script_name, args[0]);
5428
5429 // Find the requested script.
5430 Handle<Object> result =
5431 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
5432 return *result;
5433}
5434
5435
5436static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
5437#ifdef DEBUG
5438 HandleScope scope;
5439 ASSERT(args.length() == 1);
5440 // Get the function and make sure it is compiled.
5441 CONVERT_ARG_CHECKED(JSFunction, func, 0);
5442 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
5443 return Failure::Exception();
5444 }
5445 func->code()->PrintLn();
5446#endif // DEBUG
5447 return Heap::undefined_value();
5448}
5449
5450
5451static Object* Runtime_Abort(Arguments args) {
5452 ASSERT(args.length() == 2);
5453 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
5454 Smi::cast(args[1])->value());
5455 Top::PrintStack();
5456 OS::Abort();
5457 UNREACHABLE();
5458 return NULL;
5459}
5460
5461
kasper.lund44510672008-07-25 07:37:58 +00005462#ifdef DEBUG
5463// ListNatives is ONLY used by the fuzz-natives.js in debug mode
5464// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005466 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005467 HandleScope scope;
5468 Handle<JSArray> result = Factory::NewJSArray(0);
5469 int index = 0;
5470#define ADD_ENTRY(Name, argc) \
5471 { \
5472 HandleScope inner; \
5473 Handle<String> name = \
5474 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
5475 Handle<JSArray> pair = Factory::NewJSArray(0); \
5476 SetElement(pair, 0, name); \
5477 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
5478 SetElement(result, index++, pair); \
5479 }
5480 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
5481#undef ADD_ENTRY
5482 return *result;
5483}
kasper.lund44510672008-07-25 07:37:58 +00005484#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005485
5486
5487static Object* Runtime_IS_VAR(Arguments args) {
5488 UNREACHABLE(); // implemented as macro in the parser
5489 return NULL;
5490}
5491
5492
5493// ----------------------------------------------------------------------------
5494// Implementation of Runtime
5495
5496#define F(name, nargs) \
5497 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
5498 static_cast<int>(Runtime::k##name) },
5499
5500static Runtime::Function Runtime_functions[] = {
5501 RUNTIME_FUNCTION_LIST(F)
5502 { NULL, NULL, NULL, 0, -1 }
5503};
5504
5505#undef F
5506
5507
5508Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
5509 ASSERT(0 <= fid && fid < kNofFunctions);
5510 return &Runtime_functions[fid];
5511}
5512
5513
5514Runtime::Function* Runtime::FunctionForName(const char* name) {
5515 for (Function* f = Runtime_functions; f->name != NULL; f++) {
5516 if (strcmp(f->name, name) == 0) {
5517 return f;
5518 }
5519 }
5520 return NULL;
5521}
5522
5523
5524void Runtime::PerformGC(Object* result) {
5525 Failure* failure = Failure::cast(result);
5526 // Try to do a garbage collection; ignore it if it fails. The C
5527 // entry stub will throw an out-of-memory exception in that case.
5528 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
5529}
5530
5531
5532} } // namespace v8::internal