blob: 8459af16b5a2461c5e288741c1cf51c04bbd2f33 [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]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +0000324 int index = field->value();
325 int offset = index * kPointerSize + HeapObject::kHeaderSize;
326 InstanceType type = templ->map()->instance_type();
327 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
328 type == OBJECT_TEMPLATE_INFO_TYPE);
329 RUNTIME_ASSERT(offset > 0);
330 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
331 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
332 } else {
333 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
334 }
335 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336}
337
338
339static Object* ThrowRedeclarationError(const char* type, Handle<String> name) {
340 HandleScope scope;
341 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type));
342 Handle<Object> args[2] = { type_handle, name };
343 Handle<Object> error =
344 Factory::NewTypeError("redeclaration", HandleVector(args, 2));
345 return Top::Throw(*error);
346}
347
348
349static Object* Runtime_DeclareGlobals(Arguments args) {
350 HandleScope scope;
351 Handle<GlobalObject> global = Handle<GlobalObject>(Top::context()->global());
352
353 CONVERT_ARG_CHECKED(FixedArray, pairs, 0);
354 Handle<Context> context = args.at<Context>(1);
355 bool is_eval = Smi::cast(args[2])->value() == 1;
356
357 // Compute the property attributes. According to ECMA-262, section
358 // 13, page 71, the property must be read-only and
359 // non-deletable. However, neither SpiderMonkey nor KJS creates the
360 // property as read-only, so we don't either.
361 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
362
363 // Only optimize the object if we intend to add more than 5 properties.
364 OptimizedObjectForAddingMultipleProperties ba(global, pairs->length()/2 > 5);
365
366 // Traverse the name/value pairs and set the properties.
367 int length = pairs->length();
368 for (int i = 0; i < length; i += 2) {
369 HandleScope scope;
370 Handle<String> name(String::cast(pairs->get(i)));
371 Handle<Object> value(pairs->get(i + 1));
372
373 // We have to declare a global const property. To capture we only
374 // assign to it when evaluating the assignment for "const x =
375 // <expr>" the initial value is the hole.
376 bool is_const_property = value->IsTheHole();
377
378 if (value->IsUndefined() || is_const_property) {
379 // Lookup the property in the global object, and don't set the
380 // value of the variable if the property is already there.
381 LookupResult lookup;
382 global->Lookup(*name, &lookup);
383 if (lookup.IsProperty()) {
384 // Determine if the property is local by comparing the holder
385 // against the global object. The information will be used to
386 // avoid throwing re-declaration errors when declaring
387 // variables or constants that exist in the prototype chain.
388 bool is_local = (*global == lookup.holder());
389 // Get the property attributes and determine if the property is
390 // read-only.
391 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
392 bool is_read_only = (attributes & READ_ONLY) != 0;
393 if (lookup.type() == INTERCEPTOR) {
394 // If the interceptor says the property is there, we
395 // just return undefined without overwriting the property.
396 // Otherwise, we continue to setting the property.
397 if (attributes != ABSENT) {
398 // Check if the existing property conflicts with regards to const.
399 if (is_local && (is_read_only || is_const_property)) {
400 const char* type = (is_read_only) ? "const" : "var";
401 return ThrowRedeclarationError(type, name);
402 };
403 // The property already exists without conflicting: Go to
404 // the next declaration.
405 continue;
406 }
407 // Fall-through and introduce the absent property by using
408 // SetProperty.
409 } else {
410 if (is_local && (is_read_only || is_const_property)) {
411 const char* type = (is_read_only) ? "const" : "var";
412 return ThrowRedeclarationError(type, name);
413 }
414 // The property already exists without conflicting: Go to
415 // the next declaration.
416 continue;
417 }
418 }
419 } else {
420 // Copy the function and update its context. Use it as value.
421 Handle<JSFunction> boilerplate = Handle<JSFunction>::cast(value);
422 Handle<JSFunction> function =
423 Factory::NewFunctionFromBoilerplate(boilerplate, context);
424 value = function;
425 }
426
427 LookupResult lookup;
428 global->LocalLookup(*name, &lookup);
429
430 PropertyAttributes attributes = is_const_property
431 ? static_cast<PropertyAttributes>(base | READ_ONLY)
432 : base;
433
434 if (lookup.IsProperty()) {
435 // There's a local property that we need to overwrite because
436 // we're either declaring a function or there's an interceptor
437 // that claims the property is absent.
438
439 // Check for conflicting re-declarations. We cannot have
440 // conflicting types in case of intercepted properties because
441 // they are absent.
442 if (lookup.type() != INTERCEPTOR &&
443 (lookup.IsReadOnly() || is_const_property)) {
444 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
445 return ThrowRedeclarationError(type, name);
446 }
447 SetProperty(global, name, value, attributes);
448 } else {
449 // If a property with this name does not already exist on the
450 // global object add the property locally. We take special
451 // precautions to always add it as a local property even in case
452 // of callbacks in the prototype chain (this rules out using
453 // SetProperty). Also, we must use the handle-based version to
454 // avoid GC issues.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000455 IgnoreAttributesAndSetLocalProperty(global, name, value, attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000456 }
457 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000458
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000459 return Heap::undefined_value();
460}
461
462
463static Object* Runtime_DeclareContextSlot(Arguments args) {
464 HandleScope scope;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000465 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000466
ager@chromium.org7c537e22008-10-16 08:43:32 +0000467 CONVERT_ARG_CHECKED(Context, context, 0);
468 Handle<String> name(String::cast(args[1]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000469 PropertyAttributes mode =
ager@chromium.org7c537e22008-10-16 08:43:32 +0000470 static_cast<PropertyAttributes>(Smi::cast(args[2])->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000471 ASSERT(mode == READ_ONLY || mode == NONE);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000472 Handle<Object> initial_value(args[3]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000473
474 // Declarations are always done in the function context.
475 context = Handle<Context>(context->fcontext());
476
477 int index;
478 PropertyAttributes attributes;
479 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000480 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481 context->Lookup(name, flags, &index, &attributes);
482
483 if (attributes != ABSENT) {
484 // The name was declared before; check for conflicting
485 // re-declarations: This is similar to the code in parser.cc in
486 // the AstBuildingParser::Declare function.
487 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
488 // Functions are not read-only.
489 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
490 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
491 return ThrowRedeclarationError(type, name);
492 }
493
494 // Initialize it if necessary.
495 if (*initial_value != NULL) {
496 if (index >= 0) {
497 // The variable or constant context slot should always be in
498 // the function context; not in any outer context nor in the
499 // arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000500 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501 if (((attributes & READ_ONLY) == 0) ||
502 context->get(index)->IsTheHole()) {
503 context->set(index, *initial_value);
504 }
505 } else {
506 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000507 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508 SetProperty(context_ext, name, initial_value, mode);
509 }
510 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000511
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000513 // The property is not in the function context. It needs to be
514 // "declared" in the function context's extension context, or in the
515 // global context.
516 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000517 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000518 // The function context's extension context exists - use it.
519 context_ext = Handle<JSObject>(context->extension());
520 } else {
521 // The function context's extension context does not exists - allocate
522 // it.
523 context_ext = Factory::NewJSObject(Top::context_extension_function());
524 // And store it in the extension slot.
525 context->set_extension(*context_ext);
526 }
527 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000528
ager@chromium.org7c537e22008-10-16 08:43:32 +0000529 // Declare the property by setting it to the initial value if provided,
530 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
531 // constant declarations).
532 ASSERT(!context_ext->HasLocalProperty(*name));
533 Handle<Object> value(Heap::undefined_value());
534 if (*initial_value != NULL) value = initial_value;
535 SetProperty(context_ext, name, value, mode);
536 ASSERT(context_ext->GetLocalPropertyAttribute(*name) == mode);
537 }
538
539 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540}
541
542
543static Object* Runtime_InitializeVarGlobal(Arguments args) {
544 NoHandleAllocation nha;
545
546 // Determine if we need to assign to the variable if it already
547 // exists (based on the number of arguments).
548 RUNTIME_ASSERT(args.length() == 1 || args.length() == 2);
549 bool assign = args.length() == 2;
550
551 CONVERT_ARG_CHECKED(String, name, 0);
552 GlobalObject* global = Top::context()->global();
553
554 // According to ECMA-262, section 12.2, page 62, the property must
555 // not be deletable.
556 PropertyAttributes attributes = DONT_DELETE;
557
558 // Lookup the property locally in the global object. If it isn't
559 // there, we add the property and take special precautions to always
560 // add it as a local property even in case of callbacks in the
561 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000562 // We have IgnoreAttributesAndSetLocalProperty for this.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 LookupResult lookup;
564 global->LocalLookup(*name, &lookup);
565 if (!lookup.IsProperty()) {
566 Object* value = (assign) ? args[1] : Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000567 return global->IgnoreAttributesAndSetLocalProperty(*name,
568 value,
569 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570 }
571
572 // Determine if this is a redeclaration of something read-only.
573 if (lookup.IsReadOnly()) {
574 return ThrowRedeclarationError("const", name);
575 }
576
577 // Determine if this is a redeclaration of an intercepted read-only
578 // property and figure out if the property exists at all.
579 bool found = true;
580 PropertyType type = lookup.type();
581 if (type == INTERCEPTOR) {
582 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
583 if (intercepted == ABSENT) {
584 // The interceptor claims the property isn't there. We need to
585 // make sure to introduce it.
586 found = false;
587 } else if ((intercepted & READ_ONLY) != 0) {
588 // The property is present, but read-only. Since we're trying to
589 // overwrite it with a variable declaration we must throw a
590 // re-declaration error.
591 return ThrowRedeclarationError("const", name);
592 }
593 // Restore global object from context (in case of GC).
594 global = Top::context()->global();
595 }
596
597 if (found && !assign) {
598 // The global property is there and we're not assigning any value
599 // to it. Just return.
600 return Heap::undefined_value();
601 }
602
603 // Assign the value (or undefined) to the property.
604 Object* value = (assign) ? args[1] : Heap::undefined_value();
605 return global->SetProperty(&lookup, *name, value, attributes);
606}
607
608
609static Object* Runtime_InitializeConstGlobal(Arguments args) {
610 // All constants are declared with an initial value. The name
611 // of the constant is the first argument and the initial value
612 // is the second.
613 RUNTIME_ASSERT(args.length() == 2);
614 CONVERT_ARG_CHECKED(String, name, 0);
615 Handle<Object> value = args.at<Object>(1);
616
617 // Get the current global object from top.
618 GlobalObject* global = Top::context()->global();
619
620 // According to ECMA-262, section 12.2, page 62, the property must
621 // not be deletable. Since it's a const, it must be READ_ONLY too.
622 PropertyAttributes attributes =
623 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
624
625 // Lookup the property locally in the global object. If it isn't
626 // there, we add the property and take special precautions to always
627 // add it as a local property even in case of callbacks in the
628 // prototype chain (this rules out using SetProperty).
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000629 // We use IgnoreAttributesAndSetLocalProperty instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000630 LookupResult lookup;
631 global->LocalLookup(*name, &lookup);
632 if (!lookup.IsProperty()) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000633 return global->IgnoreAttributesAndSetLocalProperty(*name,
634 *value,
635 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636 }
637
638 // Determine if this is a redeclaration of something not
639 // read-only. In case the result is hidden behind an interceptor we
640 // need to ask it for the property attributes.
641 if (!lookup.IsReadOnly()) {
642 if (lookup.type() != INTERCEPTOR) {
643 return ThrowRedeclarationError("var", name);
644 }
645
646 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
647
648 // Throw re-declaration error if the intercepted property is present
649 // but not read-only.
650 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
651 return ThrowRedeclarationError("var", name);
652 }
653
654 // Restore global object from context (in case of GC) and continue
655 // with setting the value because the property is either absent or
656 // read-only. We also have to do redo the lookup.
657 global = Top::context()->global();
658
659 // BUG 1213579: Handle the case where we have to set a read-only
660 // property through an interceptor and only do it if it's
661 // uninitialized, e.g. the hole. Nirk...
662 global->SetProperty(*name, *value, attributes);
663 return *value;
664 }
665
666 // Set the value, but only we're assigning the initial value to a
667 // constant. For now, we determine this by checking if the
668 // current value is the hole.
669 PropertyType type = lookup.type();
670 if (type == FIELD) {
671 FixedArray* properties = global->properties();
672 int index = lookup.GetFieldIndex();
673 if (properties->get(index)->IsTheHole()) {
674 properties->set(index, *value);
675 }
676 } else if (type == NORMAL) {
677 Dictionary* dictionary = global->property_dictionary();
678 int entry = lookup.GetDictionaryEntry();
679 if (dictionary->ValueAt(entry)->IsTheHole()) {
680 dictionary->ValueAtPut(entry, *value);
681 }
682 } else {
683 // Ignore re-initialization of constants that have already been
684 // assigned a function value.
685 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
686 }
687
688 // Use the set value as the result of the operation.
689 return *value;
690}
691
692
693static Object* Runtime_InitializeConstContextSlot(Arguments args) {
694 HandleScope scope;
695 ASSERT(args.length() == 3);
696
697 Handle<Object> value(args[0]);
698 ASSERT(!value->IsTheHole());
699 CONVERT_ARG_CHECKED(Context, context, 1);
700 Handle<String> name(String::cast(args[2]));
701
702 // Initializations are always done in the function context.
703 context = Handle<Context>(context->fcontext());
704
705 int index;
706 PropertyAttributes attributes;
707 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000708 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000709 context->Lookup(name, flags, &index, &attributes);
710
711 // The property should always be present. It is always declared
712 // before being initialized through DeclareContextSlot.
713 ASSERT(attributes != ABSENT && (attributes & READ_ONLY) != 0);
714
715 // If the slot is in the context, we set it but only if it hasn't
716 // been set before.
717 if (index >= 0) {
718 // The constant context slot should always be in the function
719 // context; not in any outer context nor in the arguments object.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000720 ASSERT(holder.is_identical_to(context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721 if (context->get(index)->IsTheHole()) {
722 context->set(index, *value);
723 }
724 return *value;
725 }
726
727 // Otherwise, the slot must be in a JS object extension.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000728 Handle<JSObject> context_ext(JSObject::cast(*holder));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000729
730 // We must initialize the value only if it wasn't initialized
731 // before, e.g. for const declarations in a loop. The property has
732 // the hole value if it wasn't initialized yet. NOTE: We cannot use
733 // GetProperty() to get the current value as it 'unholes' the value.
734 LookupResult lookup;
735 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
736 ASSERT(lookup.IsProperty()); // the property was declared
737 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
738
739 PropertyType type = lookup.type();
740 if (type == FIELD) {
741 FixedArray* properties = context_ext->properties();
742 int index = lookup.GetFieldIndex();
743 if (properties->get(index)->IsTheHole()) {
744 properties->set(index, *value);
745 }
746 } else if (type == NORMAL) {
747 Dictionary* dictionary = context_ext->property_dictionary();
748 int entry = lookup.GetDictionaryEntry();
749 if (dictionary->ValueAt(entry)->IsTheHole()) {
750 dictionary->ValueAtPut(entry, *value);
751 }
752 } else {
753 // We should not reach here. Any real, named property should be
754 // either a field or a dictionary slot.
755 UNREACHABLE();
756 }
757 return *value;
758}
759
760
761static Object* Runtime_RegExpExec(Arguments args) {
762 HandleScope scope;
763 ASSERT(args.length() == 3);
ager@chromium.org236ad962008-09-25 09:45:57 +0000764 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
765 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766 CONVERT_CHECKED(String, raw_subject, args[1]);
767 Handle<String> subject(raw_subject);
768 Handle<Object> index(args[2]);
769 ASSERT(index->IsNumber());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000770 return *RegExpImpl::Exec(regexp, subject, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771}
772
773
774static Object* Runtime_RegExpExecGlobal(Arguments args) {
775 HandleScope scope;
776 ASSERT(args.length() == 2);
ager@chromium.org236ad962008-09-25 09:45:57 +0000777 CONVERT_CHECKED(JSRegExp, raw_regexp, args[0]);
778 Handle<JSRegExp> regexp(raw_regexp);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000779 CONVERT_CHECKED(String, raw_subject, args[1]);
780 Handle<String> subject(raw_subject);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000781 return *RegExpImpl::ExecGlobal(regexp, subject);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782}
783
784
785static Object* Runtime_MaterializeRegExpLiteral(Arguments args) {
786 HandleScope scope;
787 ASSERT(args.length() == 4);
788 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
789 int index = Smi::cast(args[1])->value();
790 Handle<String> pattern = args.at<String>(2);
791 Handle<String> flags = args.at<String>(3);
792
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000793 // Get the RegExp function from the context in the literals array.
794 // This is the RegExp function from the context in which the
795 // function was created. We do not use the RegExp function from the
796 // current global context because this might be the RegExp function
797 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000798 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +0000799 Handle<JSFunction>(
800 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000801 // Compute the regular expression literal.
802 bool has_pending_exception;
803 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000804 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
805 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000806 if (has_pending_exception) {
807 ASSERT(Top::has_pending_exception());
808 return Failure::Exception();
809 }
810 literals->set(index, *regexp);
811 return *regexp;
812}
813
814
815static Object* Runtime_FunctionGetName(Arguments args) {
816 NoHandleAllocation ha;
817 ASSERT(args.length() == 1);
818
819 CONVERT_CHECKED(JSFunction, f, args[0]);
820 return f->shared()->name();
821}
822
823
ager@chromium.org236ad962008-09-25 09:45:57 +0000824static Object* Runtime_FunctionSetName(Arguments args) {
825 NoHandleAllocation ha;
826 ASSERT(args.length() == 2);
827
828 CONVERT_CHECKED(JSFunction, f, args[0]);
829 CONVERT_CHECKED(String, name, args[1]);
830 f->shared()->set_name(name);
831 return Heap::undefined_value();
832}
833
834
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835static Object* Runtime_FunctionGetScript(Arguments args) {
836 HandleScope scope;
837 ASSERT(args.length() == 1);
838
839 CONVERT_CHECKED(JSFunction, fun, args[0]);
840 Handle<Object> script = Handle<Object>(fun->shared()->script());
841 if (!script->IsScript()) return Heap::undefined_value();
842
843 return *GetScriptWrapper(Handle<Script>::cast(script));
844}
845
846
847static Object* Runtime_FunctionGetSourceCode(Arguments args) {
848 NoHandleAllocation ha;
849 ASSERT(args.length() == 1);
850
851 CONVERT_CHECKED(JSFunction, f, args[0]);
852 return f->shared()->GetSourceCode();
853}
854
855
856static Object* Runtime_FunctionGetScriptSourcePosition(Arguments args) {
857 NoHandleAllocation ha;
858 ASSERT(args.length() == 1);
859
860 CONVERT_CHECKED(JSFunction, fun, args[0]);
861 int pos = fun->shared()->start_position();
862 return Smi::FromInt(pos);
863}
864
865
866static Object* Runtime_FunctionSetInstanceClassName(Arguments args) {
867 NoHandleAllocation ha;
868 ASSERT(args.length() == 2);
869
870 CONVERT_CHECKED(JSFunction, fun, args[0]);
871 CONVERT_CHECKED(String, name, args[1]);
872 fun->SetInstanceClassName(name);
873 return Heap::undefined_value();
874}
875
876
877static Object* Runtime_FunctionSetLength(Arguments args) {
878 NoHandleAllocation ha;
879 ASSERT(args.length() == 2);
880
881 CONVERT_CHECKED(JSFunction, fun, args[0]);
882 CONVERT_CHECKED(Smi, length, args[1]);
883 fun->shared()->set_length(length->value());
884 return length;
885}
886
887
888static Object* Runtime_FunctionSetPrototype(Arguments args) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000889 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000890 ASSERT(args.length() == 2);
891
892 CONVERT_CHECKED(JSFunction, fun, args[0]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000893 Object* obj = Accessors::FunctionSetPrototype(fun, args[1], NULL);
894 if (obj->IsFailure()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895 return args[0]; // return TOS
896}
897
898
899static Object* Runtime_SetCode(Arguments args) {
900 HandleScope scope;
901 ASSERT(args.length() == 2);
902
903 CONVERT_CHECKED(JSFunction, raw_target, args[0]);
904 Handle<JSFunction> target(raw_target);
905 Handle<Object> code = args.at<Object>(1);
906
907 Handle<Context> context(target->context());
908
909 if (!code->IsNull()) {
910 RUNTIME_ASSERT(code->IsJSFunction());
911 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
912 SetExpectedNofProperties(target, fun->shared()->expected_nof_properties());
913 if (!fun->is_compiled() && !CompileLazy(fun, KEEP_EXCEPTION)) {
914 return Failure::Exception();
915 }
916 // Set the code, formal parameter count, and the length of the target
917 // function.
918 target->set_code(fun->code());
919 target->shared()->set_length(fun->shared()->length());
920 target->shared()->set_formal_parameter_count(
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000921 fun->shared()->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +0000922 // Set the source code of the target function to undefined.
923 // SetCode is only used for built-in constructors like String,
924 // Array, and Object, and some web code
925 // doesn't like seeing source code for constructors.
926 target->shared()->set_script(Heap::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000927 context = Handle<Context>(fun->context());
928
929 // Make sure we get a fresh copy of the literal vector to avoid
930 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000931 int number_of_literals = fun->NumberOfLiterals();
932 Handle<FixedArray> literals =
933 Factory::NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000934 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000935 // Insert the object, regexp and array functions in the literals
936 // array prefix. These are the functions that will be used when
937 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +0000938 literals->set(JSFunction::kLiteralGlobalContextIndex,
939 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000940 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +0000941 target->set_literals(*literals, SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 }
943
944 target->set_context(*context);
945 return *target;
946}
947
948
949static Object* CharCodeAt(String* subject, Object* index) {
950 uint32_t i = 0;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000951 if (!Array::IndexFromObject(index, &i)) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000952 // Flatten the string. If someone wants to get a char at an index
953 // in a cons string, it is likely that more indices will be
954 // accessed.
955 subject->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000956 if (i >= static_cast<uint32_t>(subject->length())) return Heap::nan_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000957 return Smi::FromInt(subject->Get(i));
958}
959
960
961static Object* Runtime_StringCharCodeAt(Arguments args) {
962 NoHandleAllocation ha;
963 ASSERT(args.length() == 2);
964
965 CONVERT_CHECKED(String, subject, args[0]);
966 Object* index = args[1];
967 return CharCodeAt(subject, index);
968}
969
970
971static Object* Runtime_CharFromCode(Arguments args) {
972 NoHandleAllocation ha;
973 ASSERT(args.length() == 1);
974 uint32_t code;
975 if (Array::IndexFromObject(args[0], &code)) {
976 if (code <= 0xffff) {
977 return Heap::LookupSingleCharacterStringFromCode(code);
978 }
979 }
980 return Heap::empty_string();
981}
982
983
ager@chromium.org7c537e22008-10-16 08:43:32 +0000984// Cap on the maximal shift in the Boyer-Moore implementation. By setting a
985// limit, we can fix the size of tables.
986static const int kBMMaxShift = 0xff;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000987// Reduce alphabet to this size.
988static const int kBMAlphabetSize = 0x100;
989// For patterns below this length, the skip length of Boyer-Moore is too short
990// to compensate for the algorithmic overhead compared to simple brute force.
991static const int kBMMinPatternLength = 5;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992
ager@chromium.org7c537e22008-10-16 08:43:32 +0000993// Holds the two buffers used by Boyer-Moore string search's Good Suffix
994// shift. Only allows the last kBMMaxShift characters of the needle
995// to be indexed.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000996class BMGoodSuffixBuffers {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000997 public:
998 BMGoodSuffixBuffers() {}
999 inline void init(int needle_length) {
1000 ASSERT(needle_length > 1);
1001 int start = needle_length < kBMMaxShift ? 0 : needle_length - kBMMaxShift;
1002 int len = needle_length - start;
1003 biased_suffixes_ = suffixes_ - start;
1004 biased_good_suffix_shift_ = good_suffix_shift_ - start;
1005 for (int i = 0; i <= len; i++) {
1006 good_suffix_shift_[i] = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001008 }
1009 inline int& suffix(int index) {
1010 ASSERT(biased_suffixes_ + index >= suffixes_);
1011 return biased_suffixes_[index];
1012 }
1013 inline int& shift(int index) {
1014 ASSERT(biased_good_suffix_shift_ + index >= good_suffix_shift_);
1015 return biased_good_suffix_shift_[index];
1016 }
1017 private:
1018 int suffixes_[kBMMaxShift + 1];
1019 int good_suffix_shift_[kBMMaxShift + 1];
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001020 int* biased_suffixes_;
1021 int* biased_good_suffix_shift_;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001022 DISALLOW_COPY_AND_ASSIGN(BMGoodSuffixBuffers);
1023};
1024
1025// buffers reused by BoyerMoore
1026static int bad_char_occurence[kBMAlphabetSize];
1027static BMGoodSuffixBuffers bmgs_buffers;
1028
1029// Compute the bad-char table for Boyer-Moore in the static buffer.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001030template <typename pchar>
1031static void BoyerMoorePopulateBadCharTable(Vector<const pchar> pattern,
1032 int start) {
1033 // Run forwards to populate bad_char_table, so that *last* instance
1034 // of character equivalence class is the one registered.
1035 // Notice: Doesn't include the last character.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001036 int table_size = (sizeof(pchar) == 1) ? String::kMaxAsciiCharCode + 1
1037 : kBMAlphabetSize;
1038 if (start == 0) { // All patterns less than kBMMaxShift in length.
1039 memset(bad_char_occurence, -1, table_size * sizeof(*bad_char_occurence));
1040 } else {
1041 for (int i = 0; i < table_size; i++) {
1042 bad_char_occurence[i] = start - 1;
1043 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001044 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001045 for (int i = start; i < pattern.length() - 1; i++) {
1046 pchar c = pattern[i];
1047 int bucket = (sizeof(pchar) ==1) ? c : c % kBMAlphabetSize;
1048 bad_char_occurence[bucket] = i;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001049 }
1050}
1051
1052template <typename pchar>
1053static void BoyerMoorePopulateGoodSuffixTable(Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001054 int start) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001055 int m = pattern.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001056 int len = m - start;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001057 // Compute Good Suffix tables.
1058 bmgs_buffers.init(m);
1059
1060 bmgs_buffers.shift(m-1) = 1;
1061 bmgs_buffers.suffix(m) = m + 1;
1062 pchar last_char = pattern[m - 1];
1063 int suffix = m + 1;
1064 for (int i = m; i > start;) {
1065 for (pchar c = pattern[i - 1]; suffix <= m && c != pattern[suffix - 1];) {
1066 if (bmgs_buffers.shift(suffix) == len) {
1067 bmgs_buffers.shift(suffix) = suffix - i;
1068 }
1069 suffix = bmgs_buffers.suffix(suffix);
1070 }
1071 i--;
1072 suffix--;
1073 bmgs_buffers.suffix(i) = suffix;
1074 if (suffix == m) {
1075 // No suffix to extend, so we check against last_char only.
1076 while (i > start && pattern[i - 1] != last_char) {
1077 if (bmgs_buffers.shift(m) == len) {
1078 bmgs_buffers.shift(m) = m - i;
1079 }
1080 i--;
1081 bmgs_buffers.suffix(i) = m;
1082 }
1083 if (i > start) {
1084 i--;
1085 suffix--;
1086 bmgs_buffers.suffix(i) = suffix;
1087 }
1088 }
1089 }
1090 if (suffix < m) {
1091 for (int i = start; i <= m; i++) {
1092 if (bmgs_buffers.shift(i) == len) {
1093 bmgs_buffers.shift(i) = suffix - start;
1094 }
1095 if (i == suffix) {
1096 suffix = bmgs_buffers.suffix(suffix);
1097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 }
1099 }
1100}
1101
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001102template <typename schar, typename pchar>
1103static inline int CharOccurence(int char_code) {
1104 if (sizeof(schar) == 1) {
1105 return bad_char_occurence[char_code];
1106 }
1107 if (sizeof(pchar) == 1) {
1108 if (char_code > String::kMaxAsciiCharCode) {
1109 return -1;
1110 }
1111 return bad_char_occurence[char_code];
1112 }
1113 return bad_char_occurence[char_code % kBMAlphabetSize];
1114}
1115
1116// Restricted simplified Boyer-Moore string matching. Restricts tables to a
ager@chromium.org7c537e22008-10-16 08:43:32 +00001117// suffix of long pattern strings and handles only equivalence classes
1118// of the full alphabet. This allows us to ensure that tables take only
1119// a fixed amount of space.
1120template <typename schar, typename pchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001121static int BoyerMooreSimplified(Vector<const schar> subject,
1122 Vector<const pchar> pattern,
1123 int start_index,
1124 bool* complete) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001125 int n = subject.length();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001126 int m = pattern.length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00001127 // Only preprocess at most kBMMaxShift last characters of pattern.
1128 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001129
ager@chromium.org7c537e22008-10-16 08:43:32 +00001130 BoyerMoorePopulateBadCharTable(pattern, start);
1131
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001132 int badness = -m; // How bad we are doing without a good-suffix table.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001133 int idx; // No matches found prior to this index.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001134 pchar last_char = pattern[m - 1];
ager@chromium.org7c537e22008-10-16 08:43:32 +00001135 // Perform search
1136 for (idx = start_index; idx <= n - m;) {
1137 int j = m - 1;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001138 int c;
1139 while (last_char != (c = subject[idx + j])) {
1140 int bc_occ = CharOccurence<schar, pchar>(c);
1141 int shift = j - bc_occ;
1142 idx += shift;
1143 badness += 1 - shift; // at most zero, so badness cannot increase.
1144 if (idx > n - m) {
1145 *complete = true;
1146 return -1;
1147 }
1148 }
1149 j--;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001150 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1151 if (j < 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001152 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001153 return idx;
1154 } else {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001155 int bc_occ = CharOccurence<schar, pchar>(c);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001156 int shift = bc_occ < j ? j - bc_occ : 1;
1157 idx += shift;
1158 // Badness increases by the number of characters we have
1159 // checked, and decreases by the number of characters we
1160 // can skip by shifting. It's a measure of how we are doing
1161 // compared to reading each character exactly once.
1162 badness += (m - j) - shift;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001163 if (badness > 0) {
1164 *complete = false;
1165 return idx;
1166 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001167 }
1168 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001169 *complete = true;
1170 return -1;
1171}
ager@chromium.org7c537e22008-10-16 08:43:32 +00001172
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001173
1174template <typename schar, typename pchar>
1175static int BoyerMooreIndexOf(Vector<const schar> subject,
1176 Vector<const pchar> pattern,
1177 int idx) {
1178 int n = subject.length();
1179 int m = pattern.length();
1180 // Only preprocess at most kBMMaxShift last characters of pattern.
1181 int start = m < kBMMaxShift ? 0 : m - kBMMaxShift;
1182
1183 // Build the Good Suffix table and continue searching.
1184 BoyerMoorePopulateGoodSuffixTable(pattern, start);
1185 pchar last_char = pattern[m - 1];
1186 // Continue search from i.
1187 do {
1188 int j = m - 1;
1189 schar c;
1190 while (last_char != (c = subject[idx + j])) {
1191 int shift = j - CharOccurence<schar, pchar>(c);
1192 idx += shift;
1193 if (idx > n - m) {
1194 return -1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001195 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001196 }
1197 while (j >= 0 && pattern[j] == (c = subject[idx + j])) j--;
1198 if (j < 0) {
1199 return idx;
1200 } else if (j < start) {
1201 // we have matched more than our tables allow us to be smart about.
1202 idx += 1;
1203 } else {
1204 int gs_shift = bmgs_buffers.shift(j + 1); // Good suffix shift.
1205 int bc_occ = CharOccurence<schar, pchar>(c);
1206 int shift = j - bc_occ; // Bad-char shift.
1207 shift = (gs_shift > shift) ? gs_shift : shift;
1208 idx += shift;
1209 }
1210 } while (idx <= n - m);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001211
1212 return -1;
1213}
1214
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001215
1216template <typename schar>
ager@chromium.org7c537e22008-10-16 08:43:32 +00001217static int SingleCharIndexOf(Vector<const schar> string,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001218 uc16 pattern_char,
ager@chromium.org7c537e22008-10-16 08:43:32 +00001219 int start_index) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001220 if (sizeof(schar) == 1 && pattern_char > String::kMaxAsciiCharCode) {
1221 return -1;
1222 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001223 for (int i = start_index, n = string.length(); i < n; i++) {
1224 if (pattern_char == string[i]) {
1225 return i;
1226 }
1227 }
1228 return -1;
1229}
1230
1231// Trivial string search for shorter strings.
1232// On return, if "complete" is set to true, the return value is the
1233// final result of searching for the patter in the subject.
1234// If "complete" is set to false, the return value is the index where
1235// further checking should start, i.e., it's guaranteed that the pattern
1236// does not occur at a position prior to the returned index.
1237template <typename pchar, typename schar>
1238static int SimpleIndexOf(Vector<const schar> subject,
1239 Vector<const pchar> pattern,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001240 int idx,
1241 bool* complete) {
1242 // Badness is a count of how much work we have done. When we have
1243 // done enough work we decide it's probably worth switching to a better
1244 // algorithm.
1245 int badness = -10 - (pattern.length() << 2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001246 // We know our pattern is at least 2 characters, we cache the first so
1247 // the common case of the first character not matching is faster.
1248 pchar pattern_first_char = pattern[0];
1249
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001250 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1251 badness++;
1252 if (badness > 0) {
1253 *complete = false;
1254 return (i);
1255 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001256 if (subject[i] != pattern_first_char) continue;
1257 int j = 1;
1258 do {
1259 if (pattern[j] != subject[i+j]) {
1260 break;
1261 }
1262 j++;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001263 } while (j < pattern.length());
1264 if (j == pattern.length()) {
1265 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001266 return i;
1267 }
1268 badness += j;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001269 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001270 *complete = true;
ager@chromium.org7c537e22008-10-16 08:43:32 +00001271 return -1;
1272}
1273
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001274// Simple indexOf that never bails out. For short patterns only.
1275template <typename pchar, typename schar>
1276static int SimpleIndexOf(Vector<const schar> subject,
1277 Vector<const pchar> pattern,
1278 int idx) {
1279 pchar pattern_first_char = pattern[0];
1280 for (int i = idx, n = subject.length() - pattern.length(); i <= n; i++) {
1281 if (subject[i] != pattern_first_char) continue;
1282 int j = 1;
1283 do {
1284 if (pattern[j] != subject[i+j]) {
1285 break;
1286 }
1287 j++;
1288 } while (j < pattern.length());
1289 if (j == pattern.length()) {
1290 return i;
1291 }
1292 }
1293 return -1;
1294}
1295
1296
1297// Dispatch to different algorithms.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001298template <typename schar, typename pchar>
1299static int StringMatchStrategy(Vector<const schar> sub,
1300 Vector<const pchar> pat,
1301 int start_index) {
1302 ASSERT(pat.length() > 1);
1303
1304 // We have an ASCII haystack and a non-ASCII needle. Check if there
1305 // really is a non-ASCII character in the needle and bail out if there
1306 // is.
1307 if (sizeof(pchar) > 1 && sizeof(schar) == 1) {
1308 for (int i = 0; i < pat.length(); i++) {
1309 uc16 c = pat[i];
1310 if (c > String::kMaxAsciiCharCode) {
1311 return -1;
1312 }
1313 }
1314 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001315 if (pat.length() < kBMMinPatternLength) {
1316 // We don't believe fancy searching can ever be more efficient.
1317 // The max shift of Boyer-Moore on a pattern of this length does
1318 // not compensate for the overhead.
1319 return SimpleIndexOf(sub, pat, start_index);
1320 }
1321 // Try algorithms in order of increasing setup cost and expected performance.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001322 bool complete;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001323 int idx = SimpleIndexOf(sub, pat, start_index, &complete);
1324 if (complete) return idx;
1325 idx = BoyerMooreSimplified(sub, pat, idx, &complete);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001326 if (complete) return idx;
1327 return BoyerMooreIndexOf(sub, pat, idx);
1328}
1329
1330// Perform string match of pattern on subject, starting at start index.
1331// Caller must ensure that 0 <= start_index <= sub->length(),
1332// and should check that pat->length() + start_index <= sub->length()
1333int Runtime::StringMatch(Handle<String> sub,
1334 Handle<String> pat,
1335 int start_index) {
1336 ASSERT(0 <= start_index);
1337 ASSERT(start_index <= sub->length());
1338
ager@chromium.org236ad962008-09-25 09:45:57 +00001339 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001340 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341
ager@chromium.org7c537e22008-10-16 08:43:32 +00001342 int subject_length = sub->length();
1343 if (start_index + pattern_length > subject_length) return -1;
1344
1345 FlattenString(sub);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001346 // Searching for one specific character is common. For one
ager@chromium.org7c537e22008-10-16 08:43:32 +00001347 // character patterns linear search is necessary, so any smart
1348 // algorithm is unnecessary overhead.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 if (pattern_length == 1) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001350 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1351 if (sub->is_ascii_representation()) {
1352 return SingleCharIndexOf(sub->ToAsciiVector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001354 return SingleCharIndexOf(sub->ToUC16Vector(), pat->Get(0), start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 }
1356
ager@chromium.org7c537e22008-10-16 08:43:32 +00001357 FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00001358
ager@chromium.org7c537e22008-10-16 08:43:32 +00001359 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
1360 // dispatch on type of strings
1361 if (pat->is_ascii_representation()) {
1362 Vector<const char> pat_vector = pat->ToAsciiVector();
1363 if (sub->is_ascii_representation()) {
1364 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001365 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001366 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00001367 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001368 Vector<const uc16> pat_vector = pat->ToUC16Vector();
1369 if (sub->is_ascii_representation()) {
1370 return StringMatchStrategy(sub->ToAsciiVector(), pat_vector, start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001372 return StringMatchStrategy(sub->ToUC16Vector(), pat_vector, start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001373}
1374
1375
1376static Object* Runtime_StringIndexOf(Arguments args) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001377 HandleScope scope; // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001378 ASSERT(args.length() == 3);
1379
ager@chromium.org7c537e22008-10-16 08:43:32 +00001380 CONVERT_ARG_CHECKED(String, sub, 0);
1381 CONVERT_ARG_CHECKED(String, pat, 1);
1382
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001383 Object* index = args[2];
1384 uint32_t start_index;
1385 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1386
ager@chromium.org7c537e22008-10-16 08:43:32 +00001387 int position = Runtime::StringMatch(sub, pat, start_index);
1388 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389}
1390
1391
1392static Object* Runtime_StringLastIndexOf(Arguments args) {
1393 NoHandleAllocation ha;
1394 ASSERT(args.length() == 3);
1395
1396 CONVERT_CHECKED(String, sub, args[0]);
1397 CONVERT_CHECKED(String, pat, args[1]);
1398 Object* index = args[2];
1399
1400 sub->TryFlatten();
1401 pat->TryFlatten();
1402
1403 uint32_t start_index;
1404 if (!Array::IndexFromObject(index, &start_index)) return Smi::FromInt(-1);
1405
1406 uint32_t pattern_length = pat->length();
1407 uint32_t sub_length = sub->length();
1408
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001409 if (start_index + pattern_length > sub_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 start_index = sub_length - pattern_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001411 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001412
1413 for (int i = start_index; i >= 0; i--) {
1414 bool found = true;
1415 for (uint32_t j = 0; j < pattern_length; j++) {
1416 if (sub->Get(i + j) != pat->Get(j)) {
1417 found = false;
1418 break;
1419 }
1420 }
1421 if (found) return Smi::FromInt(i);
1422 }
1423
1424 return Smi::FromInt(-1);
1425}
1426
1427
1428static Object* Runtime_StringLocaleCompare(Arguments args) {
1429 NoHandleAllocation ha;
1430 ASSERT(args.length() == 2);
1431
1432 CONVERT_CHECKED(String, str1, args[0]);
1433 CONVERT_CHECKED(String, str2, args[1]);
1434
1435 if (str1 == str2) return Smi::FromInt(0); // Equal.
1436 int str1_length = str1->length();
1437 int str2_length = str2->length();
1438
1439 // Decide trivial cases without flattening.
1440 if (str1_length == 0) {
1441 if (str2_length == 0) return Smi::FromInt(0); // Equal.
1442 return Smi::FromInt(-str2_length);
1443 } else {
1444 if (str2_length == 0) return Smi::FromInt(str1_length);
1445 }
1446
1447 int end = str1_length < str2_length ? str1_length : str2_length;
1448
1449 // No need to flatten if we are going to find the answer on the first
1450 // character. At this point we know there is at least one character
1451 // in each string, due to the trivial case handling above.
1452 int d = str1->Get(0) - str2->Get(0);
1453 if (d != 0) return Smi::FromInt(d);
1454
1455 str1->TryFlatten();
1456 str2->TryFlatten();
1457
1458 static StringInputBuffer buf1;
1459 static StringInputBuffer buf2;
1460
1461 buf1.Reset(str1);
1462 buf2.Reset(str2);
1463
1464 for (int i = 0; i < end; i++) {
1465 uint16_t char1 = buf1.GetNext();
1466 uint16_t char2 = buf2.GetNext();
1467 if (char1 != char2) return Smi::FromInt(char1 - char2);
1468 }
1469
1470 return Smi::FromInt(str1_length - str2_length);
1471}
1472
1473
1474static Object* Runtime_StringSlice(Arguments args) {
1475 NoHandleAllocation ha;
1476 ASSERT(args.length() == 3);
1477
1478 CONVERT_CHECKED(String, value, args[0]);
1479 CONVERT_DOUBLE_CHECKED(from_number, args[1]);
1480 CONVERT_DOUBLE_CHECKED(to_number, args[2]);
1481
1482 int start = FastD2I(from_number);
1483 int end = FastD2I(to_number);
1484
1485 RUNTIME_ASSERT(end >= start);
1486 RUNTIME_ASSERT(start >= 0);
1487 RUNTIME_ASSERT(end <= value->length());
1488 return value->Slice(start, end);
1489}
1490
1491
1492static Object* Runtime_NumberToRadixString(Arguments args) {
1493 NoHandleAllocation ha;
1494 ASSERT(args.length() == 2);
1495
1496 CONVERT_DOUBLE_CHECKED(value, args[0]);
1497 if (isnan(value)) {
1498 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1499 }
1500 if (isinf(value)) {
1501 if (value < 0) {
1502 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1503 }
1504 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1505 }
1506 CONVERT_DOUBLE_CHECKED(radix_number, args[1]);
1507 int radix = FastD2I(radix_number);
1508 RUNTIME_ASSERT(2 <= radix && radix <= 36);
1509 char* str = DoubleToRadixCString(value, radix);
1510 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
1511 DeleteArray(str);
1512 return result;
1513}
1514
1515
1516static Object* Runtime_NumberToFixed(Arguments args) {
1517 NoHandleAllocation ha;
1518 ASSERT(args.length() == 2);
1519
1520 CONVERT_DOUBLE_CHECKED(value, args[0]);
1521 if (isnan(value)) {
1522 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1523 }
1524 if (isinf(value)) {
1525 if (value < 0) {
1526 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1527 }
1528 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1529 }
1530 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1531 int f = FastD2I(f_number);
1532 RUNTIME_ASSERT(f >= 0);
1533 char* str = DoubleToFixedCString(value, f);
1534 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1535 DeleteArray(str);
1536 return res;
1537}
1538
1539
1540static Object* Runtime_NumberToExponential(Arguments args) {
1541 NoHandleAllocation ha;
1542 ASSERT(args.length() == 2);
1543
1544 CONVERT_DOUBLE_CHECKED(value, args[0]);
1545 if (isnan(value)) {
1546 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1547 }
1548 if (isinf(value)) {
1549 if (value < 0) {
1550 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1551 }
1552 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1553 }
1554 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1555 int f = FastD2I(f_number);
1556 RUNTIME_ASSERT(f >= -1 && f <= 20);
1557 char* str = DoubleToExponentialCString(value, f);
1558 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1559 DeleteArray(str);
1560 return res;
1561}
1562
1563
1564static Object* Runtime_NumberToPrecision(Arguments args) {
1565 NoHandleAllocation ha;
1566 ASSERT(args.length() == 2);
1567
1568 CONVERT_DOUBLE_CHECKED(value, args[0]);
1569 if (isnan(value)) {
1570 return Heap::AllocateStringFromAscii(CStrVector("NaN"));
1571 }
1572 if (isinf(value)) {
1573 if (value < 0) {
1574 return Heap::AllocateStringFromAscii(CStrVector("-Infinity"));
1575 }
1576 return Heap::AllocateStringFromAscii(CStrVector("Infinity"));
1577 }
1578 CONVERT_DOUBLE_CHECKED(f_number, args[1]);
1579 int f = FastD2I(f_number);
1580 RUNTIME_ASSERT(f >= 1 && f <= 21);
1581 char* str = DoubleToPrecisionCString(value, f);
1582 Object* res = Heap::AllocateStringFromAscii(CStrVector(str));
1583 DeleteArray(str);
1584 return res;
1585}
1586
1587
1588// Returns a single character string where first character equals
1589// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001590static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 if (index < static_cast<uint32_t>(string->length())) {
1592 string->TryFlatten();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001593 return LookupSingleCharacterStringFromCode(string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001595 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001596}
1597
1598
1599Object* Runtime::GetElementOrCharAt(Handle<Object> object, uint32_t index) {
1600 // Handle [] indexing on Strings
1601 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001602 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
1603 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 }
1605
1606 // Handle [] indexing on String objects
1607 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001608 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
1609 Handle<Object> result =
1610 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
1611 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612 }
1613
1614 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001615 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001616 return prototype->GetElement(index);
1617 }
1618
1619 return object->GetElement(index);
1620}
1621
1622
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001623Object* Runtime::GetObjectProperty(Handle<Object> object, Handle<Object> key) {
1624 HandleScope scope;
1625
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001627 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628 Handle<Object> error =
1629 Factory::NewTypeError("non_object_property_load",
1630 HandleVector(args, 2));
1631 return Top::Throw(*error);
1632 }
1633
1634 // Check if the given key is an array index.
1635 uint32_t index;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001636 if (Array::IndexFromObject(*key, &index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001637 return GetElementOrCharAt(object, index);
1638 }
1639
1640 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001641 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001642 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001643 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 bool has_pending_exception = false;
1646 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001647 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001648 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001649 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001650 }
1651
1652 // Check if the name is trivially convertable to an index and get
1653 // the element if so.
1654 if (name->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655 return GetElementOrCharAt(object, index);
1656 } else {
1657 PropertyAttributes attr;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001658 return object->GetProperty(*name, &attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001659 }
1660}
1661
1662
1663static Object* Runtime_GetProperty(Arguments args) {
1664 NoHandleAllocation ha;
1665 ASSERT(args.length() == 2);
1666
1667 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001668 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669
1670 return Runtime::GetObjectProperty(object, key);
1671}
1672
1673
ager@chromium.org7c537e22008-10-16 08:43:32 +00001674
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001675// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001676static Object* Runtime_KeyedGetProperty(Arguments args) {
1677 NoHandleAllocation ha;
1678 ASSERT(args.length() == 2);
1679
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001680 // Fast cases for getting named properties of the receiver JSObject
1681 // itself. The global proxy objects has to be excluded since
1682 // LocalLookup on the global proxy object can return a valid result
1683 // eventhough the global proxy object never has properties. This is
1684 // the case because the global proxy object forwards everything to
1685 // its hidden prototype including local lookups.
1686 if (args[0]->IsJSObject() &&
1687 !args[0]->IsJSGlobalProxy() &&
1688 args[1]->IsString()) {
1689 JSObject* receiver = JSObject::cast(args[0]);
1690 String* key = String::cast(args[1]);
1691 if (receiver->HasFastProperties()) {
1692 // Attempt to use lookup cache.
1693 Object* obj = Heap::GetKeyedLookupCache();
1694 if (obj->IsFailure()) return obj;
1695 LookupCache* cache = LookupCache::cast(obj);
1696 Map* receiver_map = receiver->map();
1697 int offset = cache->Lookup(receiver_map, key);
1698 if (offset != LookupCache::kNotFound) {
1699 Object* value = receiver->FastPropertyAt(offset);
1700 return value->IsTheHole() ? Heap::undefined_value() : value;
1701 }
1702 // Lookup cache miss. Perform lookup and update the cache if
1703 // appropriate.
1704 LookupResult result;
1705 receiver->LocalLookup(key, &result);
1706 if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
1707 int offset = result.GetFieldIndex();
1708 Object* obj = cache->Put(receiver_map, key, offset);
1709 if (obj->IsFailure()) return obj;
1710 Heap::SetKeyedLookupCache(LookupCache::cast(obj));
1711 Object* value = receiver->FastPropertyAt(offset);
1712 return value->IsTheHole() ? Heap::undefined_value() : value;
1713 }
1714 } else {
1715 // Attempt dictionary lookup.
1716 Dictionary* dictionary = receiver->property_dictionary();
1717 int entry = dictionary->FindStringEntry(key);
1718 if ((entry != DescriptorArray::kNotFound) &&
1719 (dictionary->DetailsAt(entry).type() == NORMAL)) {
1720 return dictionary->ValueAt(entry);
1721 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001722 }
1723 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001724
1725 // Fall back to GetObjectProperty.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001726 return Runtime::GetObjectProperty(args.at<Object>(0),
1727 args.at<Object>(1));
1728}
1729
1730
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001731Object* Runtime::SetObjectProperty(Handle<Object> object,
1732 Handle<Object> key,
1733 Handle<Object> value,
1734 PropertyAttributes attr) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001735 HandleScope scope;
1736
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001737 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001738 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739 Handle<Object> error =
1740 Factory::NewTypeError("non_object_property_store",
1741 HandleVector(args, 2));
1742 return Top::Throw(*error);
1743 }
1744
1745 // If the object isn't a JavaScript object, we ignore the store.
1746 if (!object->IsJSObject()) return *value;
1747
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001748 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1749
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001750 // Check if the given key is an array index.
1751 uint32_t index;
1752 if (Array::IndexFromObject(*key, &index)) {
1753 ASSERT(attr == NONE);
1754
1755 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
1756 // of a string using [] notation. We need to support this too in
1757 // JavaScript.
1758 // In the case of a String object we just need to redirect the assignment to
1759 // the underlying string if the index is in range. Since the underlying
1760 // string does nothing with the assignment then we can ignore such
1761 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001762 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001763 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001764 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001765
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001766 Handle<Object> result = SetElement(js_object, index, value);
1767 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 return *value;
1769 }
1770
1771 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001772 Handle<Object> result;
1773 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001775 result = SetElement(js_object, index, value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001776 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001777 Handle<String> key_string = Handle<String>::cast(key);
1778 key_string->TryFlatten();
1779 result = SetProperty(js_object, key_string, value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001780 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001781 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001782 return *value;
1783 }
1784
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001785 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001786 bool has_pending_exception = false;
1787 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
1788 if (has_pending_exception) return Failure::Exception();
1789 Handle<String> name = Handle<String>::cast(converted);
1790
1791 if (name->AsArrayIndex(&index)) {
1792 ASSERT(attr == NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001793 return js_object->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001794 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001795 return js_object->SetProperty(*name, *value, attr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796 }
1797}
1798
1799
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001800static Object* Runtime_SetProperty(Arguments args) {
1801 NoHandleAllocation ha;
1802 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
1803
1804 Handle<Object> object = args.at<Object>(0);
1805 Handle<Object> key = args.at<Object>(1);
1806 Handle<Object> value = args.at<Object>(2);
1807
1808 // Compute attributes.
1809 PropertyAttributes attributes = NONE;
1810 if (args.length() == 4) {
1811 CONVERT_CHECKED(Smi, value_obj, args[3]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001812 int unchecked_value = value_obj->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813 // Only attribute bits should be set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001814 RUNTIME_ASSERT(
1815 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1816 attributes = static_cast<PropertyAttributes>(unchecked_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 }
1818 return Runtime::SetObjectProperty(object, key, value, attributes);
1819}
1820
1821
1822// Set a local property, even if it is READ_ONLY. If the property does not
1823// exist, it will be added with attributes NONE.
1824static Object* Runtime_IgnoreAttributesAndSetProperty(Arguments args) {
1825 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001826 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 CONVERT_CHECKED(JSObject, object, args[0]);
1828 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001829 // Compute attributes.
1830 PropertyAttributes attributes = NONE;
1831 if (args.length() == 4) {
1832 CONVERT_CHECKED(Smi, value_obj, args[3]);
1833 int unchecked_value = value_obj->value();
1834 // Only attribute bits should be set.
1835 RUNTIME_ASSERT(
1836 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1837 attributes = static_cast<PropertyAttributes>(unchecked_value);
1838 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001839
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001840 return object->
1841 IgnoreAttributesAndSetLocalProperty(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001842}
1843
1844
1845static Object* Runtime_DeleteProperty(Arguments args) {
1846 NoHandleAllocation ha;
1847 ASSERT(args.length() == 2);
1848
1849 CONVERT_CHECKED(JSObject, object, args[0]);
1850 CONVERT_CHECKED(String, key, args[1]);
1851 return object->DeleteProperty(key);
1852}
1853
1854
1855static Object* Runtime_HasLocalProperty(Arguments args) {
1856 NoHandleAllocation ha;
1857 ASSERT(args.length() == 2);
1858 CONVERT_CHECKED(String, key, args[1]);
1859
1860 // Only JS objects can have properties.
1861 if (args[0]->IsJSObject()) {
1862 JSObject* object = JSObject::cast(args[0]);
1863 if (object->HasLocalProperty(key)) return Heap::true_value();
1864 } else if (args[0]->IsString()) {
1865 // Well, there is one exception: Handle [] on strings.
1866 uint32_t index;
1867 if (key->AsArrayIndex(&index)) {
1868 String* string = String::cast(args[0]);
1869 if (index < static_cast<uint32_t>(string->length()))
1870 return Heap::true_value();
1871 }
1872 }
1873 return Heap::false_value();
1874}
1875
1876
1877static Object* Runtime_HasProperty(Arguments args) {
1878 NoHandleAllocation na;
1879 ASSERT(args.length() == 2);
1880
1881 // Only JS objects can have properties.
1882 if (args[0]->IsJSObject()) {
1883 JSObject* object = JSObject::cast(args[0]);
1884 CONVERT_CHECKED(String, key, args[1]);
1885 if (object->HasProperty(key)) return Heap::true_value();
1886 }
1887 return Heap::false_value();
1888}
1889
1890
1891static Object* Runtime_HasElement(Arguments args) {
1892 NoHandleAllocation na;
1893 ASSERT(args.length() == 2);
1894
1895 // Only JS objects can have elements.
1896 if (args[0]->IsJSObject()) {
1897 JSObject* object = JSObject::cast(args[0]);
1898 CONVERT_CHECKED(Smi, index_obj, args[1]);
1899 uint32_t index = index_obj->value();
1900 if (object->HasElement(index)) return Heap::true_value();
1901 }
1902 return Heap::false_value();
1903}
1904
1905
1906static Object* Runtime_IsPropertyEnumerable(Arguments args) {
1907 NoHandleAllocation ha;
1908 ASSERT(args.length() == 2);
1909
1910 CONVERT_CHECKED(JSObject, object, args[0]);
1911 CONVERT_CHECKED(String, key, args[1]);
1912
1913 uint32_t index;
1914 if (key->AsArrayIndex(&index)) {
1915 return Heap::ToBoolean(object->HasElement(index));
1916 }
1917
1918 LookupResult result;
1919 object->LocalLookup(key, &result);
1920 if (!result.IsProperty()) return Heap::false_value();
1921 return Heap::ToBoolean(!result.IsDontEnum());
1922}
1923
1924
1925static Object* Runtime_GetPropertyNames(Arguments args) {
1926 HandleScope scope;
1927 ASSERT(args.length() == 1);
1928
1929 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1930 Handle<JSObject> object(raw_object);
1931 return *GetKeysFor(object);
1932}
1933
1934
1935// Returns either a FixedArray as Runtime_GetPropertyNames,
1936// or, if the given object has an enum cache that contains
1937// all enumerable properties of the object and its prototypes
1938// have none, the map of the object. This is used to speed up
1939// the check for deletions during a for-in.
1940static Object* Runtime_GetPropertyNamesFast(Arguments args) {
1941 ASSERT(args.length() == 1);
1942
1943 CONVERT_CHECKED(JSObject, raw_object, args[0]);
1944
1945 if (raw_object->IsSimpleEnum()) return raw_object->map();
1946
1947 HandleScope scope;
1948 Handle<JSObject> object(raw_object);
1949 Handle<FixedArray> content = GetKeysInFixedArrayFor(object);
1950
1951 // Test again, since cache may have been built by preceding call.
1952 if (object->IsSimpleEnum()) return object->map();
1953
1954 return *content;
1955}
1956
1957
1958static Object* Runtime_GetArgumentsProperty(Arguments args) {
1959 NoHandleAllocation ha;
1960 ASSERT(args.length() == 1);
1961
1962 // Compute the frame holding the arguments.
1963 JavaScriptFrameIterator it;
1964 it.AdvanceToArgumentsFrame();
1965 JavaScriptFrame* frame = it.frame();
1966
1967 // Get the actual number of provided arguments.
1968 const uint32_t n = frame->GetProvidedParametersCount();
1969
1970 // Try to convert the key to an index. If successful and within
1971 // index return the the argument from the frame.
1972 uint32_t index;
1973 if (Array::IndexFromObject(args[0], &index) && index < n) {
1974 return frame->GetParameter(index);
1975 }
1976
1977 // Convert the key to a string.
1978 HandleScope scope;
1979 bool exception = false;
1980 Handle<Object> converted =
1981 Execution::ToString(args.at<Object>(0), &exception);
1982 if (exception) return Failure::Exception();
1983 Handle<String> key = Handle<String>::cast(converted);
1984
1985 // Try to convert the string key into an array index.
1986 if (key->AsArrayIndex(&index)) {
1987 if (index < n) {
1988 return frame->GetParameter(index);
1989 } else {
1990 return Top::initial_object_prototype()->GetElement(index);
1991 }
1992 }
1993
1994 // Handle special arguments properties.
1995 if (key->Equals(Heap::length_symbol())) return Smi::FromInt(n);
1996 if (key->Equals(Heap::callee_symbol())) return frame->function();
1997
1998 // Lookup in the initial Object.prototype object.
1999 return Top::initial_object_prototype()->GetProperty(*key);
2000}
2001
2002
2003static Object* Runtime_ToBool(Arguments args) {
2004 NoHandleAllocation ha;
2005 ASSERT(args.length() == 1);
2006
2007 return args[0]->ToBoolean();
2008}
2009
2010
2011// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
2012// Possible optimizations: put the type string into the oddballs.
2013static Object* Runtime_Typeof(Arguments args) {
2014 NoHandleAllocation ha;
2015
2016 Object* obj = args[0];
2017 if (obj->IsNumber()) return Heap::number_symbol();
2018 HeapObject* heap_obj = HeapObject::cast(obj);
2019
2020 // typeof an undetectable object is 'undefined'
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002021 if (heap_obj->map()->is_undetectable()) return Heap::undefined_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022
2023 InstanceType instance_type = heap_obj->map()->instance_type();
2024 if (instance_type < FIRST_NONSTRING_TYPE) {
2025 return Heap::string_symbol();
2026 }
2027
2028 switch (instance_type) {
2029 case ODDBALL_TYPE:
2030 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
2031 return Heap::boolean_symbol();
2032 }
2033 if (heap_obj->IsNull()) {
2034 return Heap::object_symbol();
2035 }
2036 ASSERT(heap_obj->IsUndefined());
2037 return Heap::undefined_symbol();
2038 case JS_FUNCTION_TYPE:
2039 return Heap::function_symbol();
2040 default:
2041 // For any kind of object not handled above, the spec rule for
2042 // host objects gives that it is okay to return "object"
2043 return Heap::object_symbol();
2044 }
2045}
2046
2047
2048static Object* Runtime_StringToNumber(Arguments args) {
2049 NoHandleAllocation ha;
2050 ASSERT(args.length() == 1);
2051 CONVERT_CHECKED(String, subject, args[0]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002052 subject->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002053 return Heap::NumberFromDouble(StringToDouble(subject, ALLOW_HEX));
2054}
2055
2056
2057static Object* Runtime_StringFromCharCodeArray(Arguments args) {
2058 NoHandleAllocation ha;
2059 ASSERT(args.length() == 1);
2060
2061 CONVERT_CHECKED(JSArray, codes, args[0]);
2062 int length = Smi::cast(codes->length())->value();
2063
2064 // Check if the string can be ASCII.
2065 int i;
2066 for (i = 0; i < length; i++) {
2067 Object* element = codes->GetElement(i);
2068 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2069 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
2070 break;
2071 }
2072
2073 Object* object = NULL;
2074 if (i == length) { // The string is ASCII.
2075 object = Heap::AllocateRawAsciiString(length);
2076 } else { // The string is not ASCII.
2077 object = Heap::AllocateRawTwoByteString(length);
2078 }
2079
2080 if (object->IsFailure()) return object;
2081 String* result = String::cast(object);
2082 for (int i = 0; i < length; i++) {
2083 Object* element = codes->GetElement(i);
2084 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
2085 result->Set(i, chr & 0xffff);
2086 }
2087 return result;
2088}
2089
2090
2091// kNotEscaped is generated by the following:
2092//
2093// #!/bin/perl
2094// for (my $i = 0; $i < 256; $i++) {
2095// print "\n" if $i % 16 == 0;
2096// my $c = chr($i);
2097// my $escaped = 1;
2098// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
2099// print $escaped ? "0, " : "1, ";
2100// }
2101
2102
2103static bool IsNotEscaped(uint16_t character) {
2104 // Only for 8 bit characters, the rest are always escaped (in a different way)
2105 ASSERT(character < 256);
2106 static const char kNotEscaped[256] = {
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, 1, 1, 0, 1, 1, 1,
2110 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
2111 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2112 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
2113 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
2114 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
2115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2123 };
2124 return kNotEscaped[character] != 0;
2125}
2126
2127
2128static Object* Runtime_URIEscape(Arguments args) {
2129 const char hex_chars[] = "0123456789ABCDEF";
2130 NoHandleAllocation ha;
2131 ASSERT(args.length() == 1);
2132 CONVERT_CHECKED(String, source, args[0]);
2133
2134 source->TryFlatten();
2135
2136 int escaped_length = 0;
2137 int length = source->length();
2138 {
2139 Access<StringInputBuffer> buffer(&string_input_buffer);
2140 buffer->Reset(source);
2141 while (buffer->has_more()) {
2142 uint16_t character = buffer->GetNext();
2143 if (character >= 256) {
2144 escaped_length += 6;
2145 } else if (IsNotEscaped(character)) {
2146 escaped_length++;
2147 } else {
2148 escaped_length += 3;
2149 }
2150 // We don't allow strings that are longer than Smi range.
2151 if (!Smi::IsValid(escaped_length)) {
2152 Top::context()->mark_out_of_memory();
2153 return Failure::OutOfMemoryException();
2154 }
2155 }
2156 }
2157 // No length change implies no change. Return original string if no change.
2158 if (escaped_length == length) {
2159 return source;
2160 }
2161 Object* o = Heap::AllocateRawAsciiString(escaped_length);
2162 if (o->IsFailure()) return o;
2163 String* destination = String::cast(o);
2164 int dest_position = 0;
2165
2166 Access<StringInputBuffer> buffer(&string_input_buffer);
2167 buffer->Rewind();
2168 while (buffer->has_more()) {
2169 uint16_t character = buffer->GetNext();
2170 if (character >= 256) {
2171 destination->Set(dest_position, '%');
2172 destination->Set(dest_position+1, 'u');
2173 destination->Set(dest_position+2, hex_chars[character >> 12]);
2174 destination->Set(dest_position+3, hex_chars[(character >> 8) & 0xf]);
2175 destination->Set(dest_position+4, hex_chars[(character >> 4) & 0xf]);
2176 destination->Set(dest_position+5, hex_chars[character & 0xf]);
2177 dest_position += 6;
2178 } else if (IsNotEscaped(character)) {
2179 destination->Set(dest_position, character);
2180 dest_position++;
2181 } else {
2182 destination->Set(dest_position, '%');
2183 destination->Set(dest_position+1, hex_chars[character >> 4]);
2184 destination->Set(dest_position+2, hex_chars[character & 0xf]);
2185 dest_position += 3;
2186 }
2187 }
2188 return destination;
2189}
2190
2191
2192static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
2193 static const signed char kHexValue['g'] = {
2194 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2195 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2196 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2197 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
2198 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2199 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
2200 -1, 10, 11, 12, 13, 14, 15 };
2201
2202 if (character1 > 'f') return -1;
2203 int hi = kHexValue[character1];
2204 if (hi == -1) return -1;
2205 if (character2 > 'f') return -1;
2206 int lo = kHexValue[character2];
2207 if (lo == -1) return -1;
2208 return (hi << 4) + lo;
2209}
2210
2211
2212static inline int Unescape(String* source, int i, int length, int* step) {
2213 uint16_t character = source->Get(i);
2214 int32_t hi, lo;
2215 if (character == '%' &&
2216 i <= length - 6 &&
2217 source->Get(i + 1) == 'u' &&
2218 (hi = TwoDigitHex(source->Get(i + 2), source->Get(i + 3))) != -1 &&
2219 (lo = TwoDigitHex(source->Get(i + 4), source->Get(i + 5))) != -1) {
2220 *step = 6;
2221 return (hi << 8) + lo;
2222 } else if (character == '%' &&
2223 i <= length - 3 &&
2224 (lo = TwoDigitHex(source->Get(i + 1), source->Get(i + 2))) != -1) {
2225 *step = 3;
2226 return lo;
2227 } else {
2228 *step = 1;
2229 return character;
2230 }
2231}
2232
2233
2234static Object* Runtime_URIUnescape(Arguments args) {
2235 NoHandleAllocation ha;
2236 ASSERT(args.length() == 1);
2237 CONVERT_CHECKED(String, source, args[0]);
2238
2239 source->TryFlatten();
2240
2241 bool ascii = true;
2242 int length = source->length();
2243
2244 int unescaped_length = 0;
2245 for (int i = 0; i < length; unescaped_length++) {
2246 int step;
2247 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode)
2248 ascii = false;
2249 i += step;
2250 }
2251
2252 // No length change implies no change. Return original string if no change.
2253 if (unescaped_length == length)
2254 return source;
2255
2256 Object* o = ascii ?
2257 Heap::AllocateRawAsciiString(unescaped_length) :
2258 Heap::AllocateRawTwoByteString(unescaped_length);
2259 if (o->IsFailure()) return o;
2260 String* destination = String::cast(o);
2261
2262 int dest_position = 0;
2263 for (int i = 0; i < length; dest_position++) {
2264 int step;
2265 destination->Set(dest_position, Unescape(source, i, length, &step));
2266 i += step;
2267 }
2268 return destination;
2269}
2270
2271
2272static Object* Runtime_StringParseInt(Arguments args) {
2273 NoHandleAllocation ha;
2274
2275 CONVERT_CHECKED(String, s, args[0]);
2276 CONVERT_DOUBLE_CHECKED(n, args[1]);
2277 int radix = FastD2I(n);
2278
2279 s->TryFlatten();
2280
2281 int len = s->length();
2282 int i;
2283
2284 // Skip leading white space.
2285 for (i = 0; i < len && Scanner::kIsWhiteSpace.get(s->Get(i)); i++) ;
2286 if (i == len) return Heap::nan_value();
2287
2288 // Compute the sign (default to +).
2289 int sign = 1;
2290 if (s->Get(i) == '-') {
2291 sign = -1;
2292 i++;
2293 } else if (s->Get(i) == '+') {
2294 i++;
2295 }
2296
2297 // Compute the radix if 0.
2298 if (radix == 0) {
2299 radix = 10;
2300 if (i < len && s->Get(i) == '0') {
2301 radix = 8;
2302 if (i + 1 < len) {
2303 int c = s->Get(i + 1);
2304 if (c == 'x' || c == 'X') {
2305 radix = 16;
2306 i += 2;
2307 }
2308 }
2309 }
2310 } else if (radix == 16) {
2311 // Allow 0x or 0X prefix if radix is 16.
2312 if (i + 1 < len && s->Get(i) == '0') {
2313 int c = s->Get(i + 1);
2314 if (c == 'x' || c == 'X') i += 2;
2315 }
2316 }
2317
2318 RUNTIME_ASSERT(2 <= radix && radix <= 36);
2319 double value;
2320 int end_index = StringToInt(s, i, radix, &value);
2321 if (end_index != i) {
2322 return Heap::NumberFromDouble(sign * value);
2323 }
2324 return Heap::nan_value();
2325}
2326
2327
2328static Object* Runtime_StringParseFloat(Arguments args) {
2329 NoHandleAllocation ha;
2330 CONVERT_CHECKED(String, str, args[0]);
2331
2332 // ECMA-262 section 15.1.2.3, empty string is NaN
2333 double value = StringToDouble(str, ALLOW_TRAILING_JUNK, OS::nan_value());
2334
2335 // Create a number object from the value.
2336 return Heap::NumberFromDouble(value);
2337}
2338
2339
2340static unibrow::Mapping<unibrow::ToUppercase, 128> to_upper_mapping;
2341static unibrow::Mapping<unibrow::ToLowercase, 128> to_lower_mapping;
2342
2343
2344template <class Converter>
2345static Object* ConvertCase(Arguments args,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002346 unibrow::Mapping<Converter, 128>* mapping) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002347 NoHandleAllocation ha;
2348
2349 CONVERT_CHECKED(String, s, args[0]);
2350 int raw_string_length = s->length();
2351 // Assume that the string is not empty; we need this assumption later
2352 if (raw_string_length == 0) return s;
2353 int length = raw_string_length;
2354
2355 s->TryFlatten();
2356
2357 // We try this twice, once with the assumption that the result is
2358 // no longer than the input and, if that assumption breaks, again
2359 // with the exact length. This is implemented using a goto back
2360 // to this label if we discover that the assumption doesn't hold.
2361 // I apologize sincerely for this and will give a vaffel-is to
mads.s.ager31e71382008-08-13 09:32:07 +00002362 // the first person who can implement it in a nicer way.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363 try_convert:
2364
2365 // Allocate the resulting string.
2366 //
2367 // NOTE: This assumes that the upper/lower case of an ascii
2368 // character is also ascii. This is currently the case, but it
2369 // might break in the future if we implement more context and locale
2370 // dependent upper/lower conversions.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002371 Object* o = s->IsAsciiRepresentation()
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002372 ? Heap::AllocateRawAsciiString(length)
2373 : Heap::AllocateRawTwoByteString(length);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002374 if (o->IsFailure()) return o;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002375 String* result = String::cast(o);
2376 bool has_changed_character = false;
2377
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002378 // Convert all characters to upper case, assuming that they will fit
2379 // in the buffer
2380 Access<StringInputBuffer> buffer(&string_input_buffer);
2381 buffer->Reset(s);
2382 unibrow::uchar chars[unibrow::kMaxCaseConvertedSize];
2383 int i = 0;
2384 // We can assume that the string is not empty
2385 uc32 current = buffer->GetNext();
2386 while (i < length) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002387 bool has_next = buffer->has_more();
2388 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002389 int char_length = mapping->get(current, next, chars);
2390 if (char_length == 0) {
2391 // The case conversion of this character is the character itself.
2392 result->Set(i, current);
2393 i++;
2394 } else if (char_length == 1) {
2395 // Common case: converting the letter resulted in one character.
2396 ASSERT(static_cast<uc32>(chars[0]) != current);
2397 result->Set(i, chars[0]);
2398 has_changed_character = true;
2399 i++;
2400 } else if (length == raw_string_length) {
2401 // We've assumed that the result would be as long as the
2402 // input but here is a character that converts to several
2403 // characters. No matter, we calculate the exact length
2404 // of the result and try the whole thing again.
2405 //
2406 // Note that this leaves room for optimization. We could just
2407 // memcpy what we already have to the result string. Also,
2408 // the result string is the last object allocated we could
2409 // "realloc" it and probably, in the vast majority of cases,
2410 // extend the existing string to be able to hold the full
2411 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002412 int next_length = 0;
2413 if (has_next) {
2414 next_length = mapping->get(next, 0, chars);
2415 if (next_length == 0) next_length = 1;
2416 }
2417 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002418 while (buffer->has_more()) {
2419 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002420 // NOTE: we use 0 as the next character here because, while
2421 // the next character may affect what a character converts to,
2422 // it does not in any case affect the length of what it convert
2423 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002424 int char_length = mapping->get(current, 0, chars);
2425 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002426 current_length += char_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002427 }
2428 length = current_length;
2429 goto try_convert;
2430 } else {
2431 for (int j = 0; j < char_length; j++) {
2432 result->Set(i, chars[j]);
2433 i++;
2434 }
2435 has_changed_character = true;
2436 }
2437 current = next;
2438 }
2439 if (has_changed_character) {
2440 return result;
2441 } else {
2442 // If we didn't actually change anything in doing the conversion
2443 // we simple return the result and let the converted string
2444 // become garbage; there is no reason to keep two identical strings
2445 // alive.
2446 return s;
2447 }
2448}
2449
2450
2451static Object* Runtime_StringToLowerCase(Arguments args) {
2452 return ConvertCase<unibrow::ToLowercase>(args, &to_lower_mapping);
2453}
2454
2455
2456static Object* Runtime_StringToUpperCase(Arguments args) {
2457 return ConvertCase<unibrow::ToUppercase>(args, &to_upper_mapping);
2458}
2459
2460
2461static Object* Runtime_ConsStringFst(Arguments args) {
2462 NoHandleAllocation ha;
2463
2464 CONVERT_CHECKED(ConsString, str, args[0]);
2465 return str->first();
2466}
2467
2468
2469static Object* Runtime_ConsStringSnd(Arguments args) {
2470 NoHandleAllocation ha;
2471
2472 CONVERT_CHECKED(ConsString, str, args[0]);
2473 return str->second();
2474}
2475
2476
2477static Object* Runtime_NumberToString(Arguments args) {
2478 NoHandleAllocation ha;
2479 ASSERT(args.length() == 1);
2480
2481 Object* number = args[0];
2482 RUNTIME_ASSERT(number->IsNumber());
2483
2484 Object* cached = Heap::GetNumberStringCache(number);
2485 if (cached != Heap::undefined_value()) {
2486 return cached;
2487 }
2488
2489 char arr[100];
2490 Vector<char> buffer(arr, ARRAY_SIZE(arr));
2491 const char* str;
2492 if (number->IsSmi()) {
2493 int num = Smi::cast(number)->value();
2494 str = IntToCString(num, buffer);
2495 } else {
2496 double num = HeapNumber::cast(number)->value();
2497 str = DoubleToCString(num, buffer);
2498 }
2499 Object* result = Heap::AllocateStringFromAscii(CStrVector(str));
2500
2501 if (!result->IsFailure()) {
2502 Heap::SetNumberStringCache(number, String::cast(result));
2503 }
2504 return result;
2505}
2506
2507
2508static Object* Runtime_NumberToInteger(Arguments args) {
2509 NoHandleAllocation ha;
2510 ASSERT(args.length() == 1);
2511
2512 Object* obj = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002513 if (obj->IsSmi()) return obj;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002514 CONVERT_DOUBLE_CHECKED(number, obj);
2515 return Heap::NumberFromDouble(DoubleToInteger(number));
2516}
2517
2518
2519static Object* Runtime_NumberToJSUint32(Arguments args) {
2520 NoHandleAllocation ha;
2521 ASSERT(args.length() == 1);
2522
2523 Object* obj = args[0];
2524 if (obj->IsSmi() && Smi::cast(obj)->value() >= 0) return obj;
2525 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, obj);
2526 return Heap::NumberFromUint32(number);
2527}
2528
2529
2530static Object* Runtime_NumberToJSInt32(Arguments args) {
2531 NoHandleAllocation ha;
2532 ASSERT(args.length() == 1);
2533
2534 Object* obj = args[0];
2535 if (obj->IsSmi()) return obj;
2536 CONVERT_DOUBLE_CHECKED(number, obj);
2537 return Heap::NumberFromInt32(DoubleToInt32(number));
2538}
2539
2540
2541static Object* Runtime_NumberAdd(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_NumberSub(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
2561static Object* Runtime_NumberMul(Arguments args) {
2562 NoHandleAllocation ha;
2563 ASSERT(args.length() == 2);
2564
2565 CONVERT_DOUBLE_CHECKED(x, args[0]);
2566 CONVERT_DOUBLE_CHECKED(y, args[1]);
2567 return Heap::AllocateHeapNumber(x * y);
2568}
2569
2570
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002571static Object* Runtime_NumberUnaryMinus(Arguments args) {
2572 NoHandleAllocation ha;
2573 ASSERT(args.length() == 1);
2574
2575 CONVERT_DOUBLE_CHECKED(x, args[0]);
2576 return Heap::AllocateHeapNumber(-x);
2577}
2578
2579
2580static Object* Runtime_NumberDiv(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 return Heap::NewNumberFromDouble(x / y);
2587}
2588
2589
2590static Object* Runtime_NumberMod(Arguments args) {
2591 NoHandleAllocation ha;
2592 ASSERT(args.length() == 2);
2593
2594 CONVERT_DOUBLE_CHECKED(x, args[0]);
2595 CONVERT_DOUBLE_CHECKED(y, args[1]);
2596
2597#ifdef WIN32
2598 // Workaround MS fmod bugs. ECMA-262 says:
2599 // dividend is finite and divisor is an infinity => result equals dividend
2600 // dividend is a zero and divisor is nonzero finite => result equals dividend
2601 if (!(isfinite(x) && (!isfinite(y) && !isnan(y))) &&
2602 !(x == 0 && (y != 0 && isfinite(y))))
2603#endif
2604 x = fmod(x, y);
2605 // NewNumberFromDouble may return a Smi instead of a Number object
2606 return Heap::NewNumberFromDouble(x);
2607}
2608
2609
2610static Object* Runtime_StringAdd(Arguments args) {
2611 NoHandleAllocation ha;
2612 ASSERT(args.length() == 2);
2613
2614 CONVERT_CHECKED(String, str1, args[0]);
2615 CONVERT_CHECKED(String, str2, args[1]);
2616 int len1 = str1->length();
2617 int len2 = str2->length();
2618 if (len1 == 0) return str2;
2619 if (len2 == 0) return str1;
2620 int length_sum = len1 + len2;
2621 // Make sure that an out of memory exception is thrown if the length
2622 // of the new cons string is too large to fit in a Smi.
2623 if (length_sum > Smi::kMaxValue || length_sum < 0) {
2624 Top::context()->mark_out_of_memory();
2625 return Failure::OutOfMemoryException();
2626 }
2627 return Heap::AllocateConsString(str1, str2);
2628}
2629
2630
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002631template<typename sinkchar>
2632static inline void StringBuilderConcatHelper(String* special,
2633 sinkchar* sink,
2634 FixedArray* fixed_array,
2635 int array_length) {
2636 int position = 0;
2637 for (int i = 0; i < array_length; i++) {
2638 Object* element = fixed_array->get(i);
2639 if (element->IsSmi()) {
2640 int len = Smi::cast(element)->value();
2641 int pos = len >> 11;
2642 len &= 0x7ff;
2643 String::WriteToFlat(special, sink + position, pos, pos + len);
2644 position += len;
2645 } else {
2646 String* string = String::cast(element);
2647 int element_length = string->length();
2648 String::WriteToFlat(string, sink + position, 0, element_length);
2649 position += element_length;
2650 }
2651 }
2652}
2653
2654
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002655static Object* Runtime_StringBuilderConcat(Arguments args) {
2656 NoHandleAllocation ha;
2657 ASSERT(args.length() == 2);
2658 CONVERT_CHECKED(JSArray, array, args[0]);
2659 CONVERT_CHECKED(String, special, args[1]);
2660 int special_length = special->length();
2661 Object* smi_array_length = array->length();
2662 if (!smi_array_length->IsSmi()) {
2663 Top::context()->mark_out_of_memory();
2664 return Failure::OutOfMemoryException();
2665 }
2666 int array_length = Smi::cast(smi_array_length)->value();
2667 if (!array->HasFastElements()) {
2668 return Top::Throw(Heap::illegal_argument_symbol());
2669 }
2670 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002671 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002672 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002673 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002674
2675 if (array_length == 0) {
2676 return Heap::empty_string();
2677 } else if (array_length == 1) {
2678 Object* first = fixed_array->get(0);
2679 if (first->IsString()) return first;
2680 }
2681
ager@chromium.org7c537e22008-10-16 08:43:32 +00002682 bool ascii = special->IsAsciiRepresentation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002683 int position = 0;
2684 for (int i = 0; i < array_length; i++) {
2685 Object* elt = fixed_array->get(i);
2686 if (elt->IsSmi()) {
2687 int len = Smi::cast(elt)->value();
2688 int pos = len >> 11;
2689 len &= 0x7ff;
2690 if (pos + len > special_length) {
2691 return Top::Throw(Heap::illegal_argument_symbol());
2692 }
2693 position += len;
2694 } else if (elt->IsString()) {
2695 String* element = String::cast(elt);
2696 int element_length = element->length();
2697 if (!Smi::IsValid(element_length + position)) {
2698 Top::context()->mark_out_of_memory();
2699 return Failure::OutOfMemoryException();
2700 }
2701 position += element_length;
ager@chromium.org7c537e22008-10-16 08:43:32 +00002702 if (ascii && !element->IsAsciiRepresentation()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002703 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002704 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002705 } else {
2706 return Top::Throw(Heap::illegal_argument_symbol());
2707 }
2708 }
2709
2710 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002711 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002712
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002713 if (ascii) {
2714 object = Heap::AllocateRawAsciiString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002715 if (object->IsFailure()) return object;
2716 SeqAsciiString* answer = SeqAsciiString::cast(object);
2717 StringBuilderConcatHelper(special,
2718 answer->GetChars(),
2719 fixed_array,
2720 array_length);
2721 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002722 } else {
2723 object = Heap::AllocateRawTwoByteString(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002724 if (object->IsFailure()) return object;
2725 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
2726 StringBuilderConcatHelper(special,
2727 answer->GetChars(),
2728 fixed_array,
2729 array_length);
2730 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002731 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002732}
2733
2734
2735static Object* Runtime_NumberOr(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_NumberAnd(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_NumberXor(Arguments args) {
2756 NoHandleAllocation ha;
2757 ASSERT(args.length() == 2);
2758
2759 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2760 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2761 return Heap::NumberFromInt32(x ^ y);
2762}
2763
2764
2765static Object* Runtime_NumberNot(Arguments args) {
2766 NoHandleAllocation ha;
2767 ASSERT(args.length() == 1);
2768
2769 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2770 return Heap::NumberFromInt32(~x);
2771}
2772
2773
2774static Object* Runtime_NumberShl(Arguments args) {
2775 NoHandleAllocation ha;
2776 ASSERT(args.length() == 2);
2777
2778 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2779 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2780 return Heap::NumberFromInt32(x << (y & 0x1f));
2781}
2782
2783
2784static Object* Runtime_NumberShr(Arguments args) {
2785 NoHandleAllocation ha;
2786 ASSERT(args.length() == 2);
2787
2788 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
2789 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2790 return Heap::NumberFromUint32(x >> (y & 0x1f));
2791}
2792
2793
2794static Object* Runtime_NumberSar(Arguments args) {
2795 NoHandleAllocation ha;
2796 ASSERT(args.length() == 2);
2797
2798 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
2799 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
2800 return Heap::NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
2801}
2802
2803
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804static Object* Runtime_NumberEquals(Arguments args) {
2805 NoHandleAllocation ha;
2806 ASSERT(args.length() == 2);
2807
2808 CONVERT_DOUBLE_CHECKED(x, args[0]);
2809 CONVERT_DOUBLE_CHECKED(y, args[1]);
2810 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
2811 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
2812 if (x == y) return Smi::FromInt(EQUAL);
2813 Object* result;
2814 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
2815 result = Smi::FromInt(EQUAL);
2816 } else {
2817 result = Smi::FromInt(NOT_EQUAL);
2818 }
2819 return result;
2820}
2821
2822
2823static Object* Runtime_StringEquals(Arguments args) {
2824 NoHandleAllocation ha;
2825 ASSERT(args.length() == 2);
2826
2827 CONVERT_CHECKED(String, x, args[0]);
2828 CONVERT_CHECKED(String, y, args[1]);
2829
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002830 bool not_equal = !x->Equals(y);
2831 // This is slightly convoluted because the value that signifies
2832 // equality is 0 and inequality is 1 so we have to negate the result
2833 // from String::Equals.
2834 ASSERT(not_equal == 0 || not_equal == 1);
2835 STATIC_CHECK(EQUAL == 0);
2836 STATIC_CHECK(NOT_EQUAL == 1);
2837 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002838}
2839
2840
2841static Object* Runtime_NumberCompare(Arguments args) {
2842 NoHandleAllocation ha;
2843 ASSERT(args.length() == 3);
2844
2845 CONVERT_DOUBLE_CHECKED(x, args[0]);
2846 CONVERT_DOUBLE_CHECKED(y, args[1]);
2847 if (isnan(x) || isnan(y)) return args[2];
2848 if (x == y) return Smi::FromInt(EQUAL);
2849 if (isless(x, y)) return Smi::FromInt(LESS);
2850 return Smi::FromInt(GREATER);
2851}
2852
2853
ager@chromium.org9258b6b2008-09-11 09:11:10 +00002854// Compare two Smis as if they were converted to strings and then
2855// compared lexicographically.
2856static Object* Runtime_SmiLexicographicCompare(Arguments args) {
2857 NoHandleAllocation ha;
2858 ASSERT(args.length() == 2);
2859
2860 // Arrays for the individual characters of the two Smis. Smis are
2861 // 31 bit integers and 10 decimal digits are therefore enough.
2862 static int x_elms[10];
2863 static int y_elms[10];
2864
2865 // Extract the integer values from the Smis.
2866 CONVERT_CHECKED(Smi, x, args[0]);
2867 CONVERT_CHECKED(Smi, y, args[1]);
2868 int x_value = x->value();
2869 int y_value = y->value();
2870
2871 // If the integers are equal so are the string representations.
2872 if (x_value == y_value) return Smi::FromInt(EQUAL);
2873
2874 // If one of the integers are zero the normal integer order is the
2875 // same as the lexicographic order of the string representations.
2876 if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
2877
2878 // If only one of the intergers is negative the negative number is
2879 // smallest because the char code of '-' is less than the char code
2880 // of any digit. Otherwise, we make both values positive.
2881 if (x_value < 0 || y_value < 0) {
2882 if (y_value >= 0) return Smi::FromInt(LESS);
2883 if (x_value >= 0) return Smi::FromInt(GREATER);
2884 x_value = -x_value;
2885 y_value = -y_value;
2886 }
2887
2888 // Convert the integers to arrays of their decimal digits.
2889 int x_index = 0;
2890 int y_index = 0;
2891 while (x_value > 0) {
2892 x_elms[x_index++] = x_value % 10;
2893 x_value /= 10;
2894 }
2895 while (y_value > 0) {
2896 y_elms[y_index++] = y_value % 10;
2897 y_value /= 10;
2898 }
2899
2900 // Loop through the arrays of decimal digits finding the first place
2901 // where they differ.
2902 while (--x_index >= 0 && --y_index >= 0) {
2903 int diff = x_elms[x_index] - y_elms[y_index];
2904 if (diff != 0) return Smi::FromInt(diff);
2905 }
2906
2907 // If one array is a suffix of the other array, the longest array is
2908 // the representation of the largest of the Smis in the
2909 // lexicographic ordering.
2910 return Smi::FromInt(x_index - y_index);
2911}
2912
2913
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002914static Object* Runtime_StringCompare(Arguments args) {
2915 NoHandleAllocation ha;
2916 ASSERT(args.length() == 2);
2917
2918 CONVERT_CHECKED(String, x, args[0]);
2919 CONVERT_CHECKED(String, y, args[1]);
2920
2921 // A few fast case tests before we flatten.
2922 if (x == y) return Smi::FromInt(EQUAL);
2923 if (y->length() == 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002924 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002925 return Smi::FromInt(GREATER);
2926 } else if (x->length() == 0) {
2927 return Smi::FromInt(LESS);
2928 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002929
2930 int d = x->Get(0) - y->Get(0);
2931 if (d < 0) return Smi::FromInt(LESS);
2932 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002933
2934 x->TryFlatten();
2935 y->TryFlatten();
2936
2937 static StringInputBuffer bufx;
2938 static StringInputBuffer bufy;
2939 bufx.Reset(x);
2940 bufy.Reset(y);
2941 while (bufx.has_more() && bufy.has_more()) {
2942 int d = bufx.GetNext() - bufy.GetNext();
2943 if (d < 0) return Smi::FromInt(LESS);
2944 else if (d > 0) return Smi::FromInt(GREATER);
2945 }
2946
2947 // x is (non-trivial) prefix of y:
2948 if (bufy.has_more()) return Smi::FromInt(LESS);
2949 // y is prefix of x:
2950 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
2951}
2952
2953
2954static Object* Runtime_Math_abs(Arguments args) {
2955 NoHandleAllocation ha;
2956 ASSERT(args.length() == 1);
2957
2958 CONVERT_DOUBLE_CHECKED(x, args[0]);
2959 return Heap::AllocateHeapNumber(fabs(x));
2960}
2961
2962
2963static Object* Runtime_Math_acos(Arguments args) {
2964 NoHandleAllocation ha;
2965 ASSERT(args.length() == 1);
2966
2967 CONVERT_DOUBLE_CHECKED(x, args[0]);
2968 return Heap::AllocateHeapNumber(acos(x));
2969}
2970
2971
2972static Object* Runtime_Math_asin(Arguments args) {
2973 NoHandleAllocation ha;
2974 ASSERT(args.length() == 1);
2975
2976 CONVERT_DOUBLE_CHECKED(x, args[0]);
2977 return Heap::AllocateHeapNumber(asin(x));
2978}
2979
2980
2981static Object* Runtime_Math_atan(Arguments args) {
2982 NoHandleAllocation ha;
2983 ASSERT(args.length() == 1);
2984
2985 CONVERT_DOUBLE_CHECKED(x, args[0]);
2986 return Heap::AllocateHeapNumber(atan(x));
2987}
2988
2989
2990static Object* Runtime_Math_atan2(Arguments args) {
2991 NoHandleAllocation ha;
2992 ASSERT(args.length() == 2);
2993
2994 CONVERT_DOUBLE_CHECKED(x, args[0]);
2995 CONVERT_DOUBLE_CHECKED(y, args[1]);
2996 double result;
2997 if (isinf(x) && isinf(y)) {
2998 // Make sure that the result in case of two infinite arguments
2999 // is a multiple of Pi / 4. The sign of the result is determined
3000 // by the first argument (x) and the sign of the second argument
3001 // determines the multiplier: one or three.
3002 static double kPiDividedBy4 = 0.78539816339744830962;
3003 int multiplier = (x < 0) ? -1 : 1;
3004 if (y < 0) multiplier *= 3;
3005 result = multiplier * kPiDividedBy4;
3006 } else {
3007 result = atan2(x, y);
3008 }
3009 return Heap::AllocateHeapNumber(result);
3010}
3011
3012
3013static Object* Runtime_Math_ceil(Arguments args) {
3014 NoHandleAllocation ha;
3015 ASSERT(args.length() == 1);
3016
3017 CONVERT_DOUBLE_CHECKED(x, args[0]);
3018 return Heap::NumberFromDouble(ceiling(x));
3019}
3020
3021
3022static Object* Runtime_Math_cos(Arguments args) {
3023 NoHandleAllocation ha;
3024 ASSERT(args.length() == 1);
3025
3026 CONVERT_DOUBLE_CHECKED(x, args[0]);
3027 return Heap::AllocateHeapNumber(cos(x));
3028}
3029
3030
3031static Object* Runtime_Math_exp(Arguments args) {
3032 NoHandleAllocation ha;
3033 ASSERT(args.length() == 1);
3034
3035 CONVERT_DOUBLE_CHECKED(x, args[0]);
3036 return Heap::AllocateHeapNumber(exp(x));
3037}
3038
3039
3040static Object* Runtime_Math_floor(Arguments args) {
3041 NoHandleAllocation ha;
3042 ASSERT(args.length() == 1);
3043
3044 CONVERT_DOUBLE_CHECKED(x, args[0]);
3045 return Heap::NumberFromDouble(floor(x));
3046}
3047
3048
3049static Object* Runtime_Math_log(Arguments args) {
3050 NoHandleAllocation ha;
3051 ASSERT(args.length() == 1);
3052
3053 CONVERT_DOUBLE_CHECKED(x, args[0]);
3054 return Heap::AllocateHeapNumber(log(x));
3055}
3056
3057
3058static Object* Runtime_Math_pow(Arguments args) {
3059 NoHandleAllocation ha;
3060 ASSERT(args.length() == 2);
3061
3062 CONVERT_DOUBLE_CHECKED(x, args[0]);
3063 CONVERT_DOUBLE_CHECKED(y, args[1]);
3064 if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
3065 return Heap::nan_value();
3066 } else if (y == 0) {
3067 return Smi::FromInt(1);
3068 } else {
3069 return Heap::AllocateHeapNumber(pow(x, y));
3070 }
3071}
3072
3073// Returns a number value with positive sign, greater than or equal to
3074// 0 but less than 1, chosen randomly.
mads.s.ager31e71382008-08-13 09:32:07 +00003075static Object* Runtime_Math_random(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003076 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003077 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003078
3079 // To get much better precision, we combine the results of two
3080 // invocations of random(). The result is computed by normalizing a
3081 // double in the range [0, RAND_MAX + 1) obtained by adding the
3082 // high-order bits in the range [0, RAND_MAX] with the low-order
3083 // bits in the range [0, 1).
3084 double lo = static_cast<double>(random()) / (RAND_MAX + 1.0);
3085 double hi = static_cast<double>(random());
3086 double result = (hi + lo) / (RAND_MAX + 1.0);
3087 ASSERT(result >= 0 && result < 1);
3088 return Heap::AllocateHeapNumber(result);
3089}
3090
3091
3092static Object* Runtime_Math_round(Arguments args) {
3093 NoHandleAllocation ha;
3094 ASSERT(args.length() == 1);
3095
3096 CONVERT_DOUBLE_CHECKED(x, args[0]);
3097 if (signbit(x) && x >= -0.5) return Heap::minus_zero_value();
3098 return Heap::NumberFromDouble(floor(x + 0.5));
3099}
3100
3101
3102static Object* Runtime_Math_sin(Arguments args) {
3103 NoHandleAllocation ha;
3104 ASSERT(args.length() == 1);
3105
3106 CONVERT_DOUBLE_CHECKED(x, args[0]);
3107 return Heap::AllocateHeapNumber(sin(x));
3108}
3109
3110
3111static Object* Runtime_Math_sqrt(Arguments args) {
3112 NoHandleAllocation ha;
3113 ASSERT(args.length() == 1);
3114
3115 CONVERT_DOUBLE_CHECKED(x, args[0]);
3116 return Heap::AllocateHeapNumber(sqrt(x));
3117}
3118
3119
3120static Object* Runtime_Math_tan(Arguments args) {
3121 NoHandleAllocation ha;
3122 ASSERT(args.length() == 1);
3123
3124 CONVERT_DOUBLE_CHECKED(x, args[0]);
3125 return Heap::AllocateHeapNumber(tan(x));
3126}
3127
3128
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003129// The NewArguments function is only used when constructing the
3130// arguments array when calling non-functions from JavaScript in
3131// runtime.js:CALL_NON_FUNCTION.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003132static Object* Runtime_NewArguments(Arguments args) {
3133 NoHandleAllocation ha;
3134 ASSERT(args.length() == 1);
3135
3136 // ECMA-262, 3rd., 10.1.8, p.39
3137 CONVERT_CHECKED(JSFunction, callee, args[0]);
3138
3139 // Compute the frame holding the arguments.
3140 JavaScriptFrameIterator it;
3141 it.AdvanceToArgumentsFrame();
3142 JavaScriptFrame* frame = it.frame();
3143
3144 const int length = frame->GetProvidedParametersCount();
3145 Object* result = Heap::AllocateArgumentsObject(callee, length);
3146 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003147 if (length > 0) {
3148 Object* obj = Heap::AllocateFixedArray(length);
3149 if (obj->IsFailure()) return obj;
3150 FixedArray* array = FixedArray::cast(obj);
3151 ASSERT(array->length() == length);
3152 WriteBarrierMode mode = array->GetWriteBarrierMode();
3153 for (int i = 0; i < length; i++) {
3154 array->set(i, frame->GetParameter(i), mode);
3155 }
3156 JSObject::cast(result)->set_elements(array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003157 }
3158 return result;
3159}
3160
3161
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003162static Object* Runtime_NewArgumentsFast(Arguments args) {
3163 NoHandleAllocation ha;
3164 ASSERT(args.length() == 3);
3165
3166 JSFunction* callee = JSFunction::cast(args[0]);
3167 Object** parameters = reinterpret_cast<Object**>(args[1]);
3168 const int length = Smi::cast(args[2])->value();
3169
3170 Object* result = Heap::AllocateArgumentsObject(callee, length);
3171 if (result->IsFailure()) return result;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003172 ASSERT(Heap::InNewSpace(result));
3173
3174 // Allocate the elements if needed.
3175 if (length > 0) {
3176 // Allocate the fixed array.
3177 Object* obj = Heap::AllocateRawFixedArray(length);
3178 if (obj->IsFailure()) return obj;
3179 reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
3180 FixedArray* array = FixedArray::cast(obj);
3181 array->set_length(length);
3182 WriteBarrierMode mode = array->GetWriteBarrierMode();
3183 for (int i = 0; i < length; i++) {
3184 array->set(i, *--parameters, mode);
3185 }
3186 JSObject::cast(result)->set_elements(FixedArray::cast(obj),
3187 SKIP_WRITE_BARRIER);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003188 }
3189 return result;
3190}
3191
3192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003193static Object* Runtime_NewClosure(Arguments args) {
3194 HandleScope scope;
3195 ASSERT(args.length() == 2);
3196 CONVERT_ARG_CHECKED(JSFunction, boilerplate, 0);
3197 CONVERT_ARG_CHECKED(Context, context, 1);
3198
3199 Handle<JSFunction> result =
3200 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3201 return *result;
3202}
3203
3204
3205static Object* Runtime_NewObject(Arguments args) {
3206 NoHandleAllocation ha;
3207 ASSERT(args.length() == 1);
3208
3209 Object* constructor = args[0];
3210 if (constructor->IsJSFunction()) {
3211 JSFunction* function = JSFunction::cast(constructor);
3212
3213 // Handle steping into constructors.
3214 if (Debug::StepInActive()) {
3215 StackFrameIterator it;
3216 it.Advance();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003217 ASSERT(it.frame()->is_construct());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003218 it.Advance();
3219 if (it.frame()->fp() == Debug::step_in_fp()) {
3220 HandleScope scope;
3221 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
3222 }
3223 }
3224
3225 if (function->has_initial_map() &&
3226 function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
3227 // The 'Function' function ignores the receiver object when
3228 // called using 'new' and creates a new JSFunction object that
3229 // is returned. The receiver object is only used for error
3230 // reporting if an error occurs when constructing the new
3231 // JSFunction. AllocateJSObject should not be used to allocate
3232 // JSFunctions since it does not properly initialize the shared
3233 // part of the function. Since the receiver is ignored anyway,
3234 // we use the global object as the receiver instead of a new
3235 // JSFunction object. This way, errors are reported the same
3236 // way whether or not 'Function' is called using 'new'.
3237 return Top::context()->global();
3238 }
3239 return Heap::AllocateJSObject(function);
3240 }
3241
3242 HandleScope scope;
3243 Handle<Object> cons(constructor);
3244 // The constructor is not a function; throw a type error.
3245 Handle<Object> type_error =
3246 Factory::NewTypeError("not_constructor", HandleVector(&cons, 1));
3247 return Top::Throw(*type_error);
3248}
3249
3250
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003251static Object* Runtime_LazyCompile(Arguments args) {
3252 HandleScope scope;
3253 ASSERT(args.length() == 1);
3254
3255 Handle<JSFunction> function = args.at<JSFunction>(0);
3256#ifdef DEBUG
3257 if (FLAG_trace_lazy) {
3258 PrintF("[lazy: ");
3259 function->shared()->name()->Print();
3260 PrintF("]\n");
3261 }
3262#endif
3263
3264 // Compile the target function.
3265 ASSERT(!function->is_compiled());
3266 if (!CompileLazy(function, KEEP_EXCEPTION)) {
3267 return Failure::Exception();
3268 }
3269
3270 return function->code();
3271}
3272
3273
3274static Object* Runtime_GetCalledFunction(Arguments args) {
3275 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00003276 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003277 StackFrameIterator it;
3278 // Get past the JS-to-C exit frame.
3279 ASSERT(it.frame()->is_exit());
3280 it.Advance();
3281 // Get past the CALL_NON_FUNCTION activation frame.
3282 ASSERT(it.frame()->is_java_script());
3283 it.Advance();
3284 // Argument adaptor frames do not copy the function; we have to skip
3285 // past them to get to the real calling frame.
3286 if (it.frame()->is_arguments_adaptor()) it.Advance();
3287 // Get the function from the top of the expression stack of the
3288 // calling frame.
3289 StandardFrame* frame = StandardFrame::cast(it.frame());
3290 int index = frame->ComputeExpressionsCount() - 1;
3291 Object* result = frame->GetExpression(index);
3292 return result;
3293}
3294
3295
3296static Object* Runtime_GetFunctionDelegate(Arguments args) {
3297 HandleScope scope;
3298 ASSERT(args.length() == 1);
3299 RUNTIME_ASSERT(!args[0]->IsJSFunction());
3300 return *Execution::GetFunctionDelegate(args.at<Object>(0));
3301}
3302
3303
3304static Object* Runtime_NewContext(Arguments args) {
3305 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003306 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003307
kasper.lund7276f142008-07-30 08:49:36 +00003308 CONVERT_CHECKED(JSFunction, function, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003309 int length = ScopeInfo<>::NumberOfContextSlots(function->code());
3310 Object* result = Heap::AllocateFunctionContext(length, function);
3311 if (result->IsFailure()) return result;
3312
3313 Top::set_context(Context::cast(result));
3314
kasper.lund7276f142008-07-30 08:49:36 +00003315 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003316}
3317
3318
3319static Object* Runtime_PushContext(Arguments args) {
3320 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00003321 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003322
3323 // Convert the object to a proper JavaScript object.
kasper.lund7276f142008-07-30 08:49:36 +00003324 Object* object = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003325 if (!object->IsJSObject()) {
3326 object = object->ToObject();
3327 if (object->IsFailure()) {
3328 if (!Failure::cast(object)->IsInternalError()) return object;
3329 HandleScope scope;
kasper.lund7276f142008-07-30 08:49:36 +00003330 Handle<Object> handle(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331 Handle<Object> result =
3332 Factory::NewTypeError("with_expression", HandleVector(&handle, 1));
3333 return Top::Throw(*result);
3334 }
3335 }
3336
3337 Object* result =
3338 Heap::AllocateWithContext(Top::context(), JSObject::cast(object));
3339 if (result->IsFailure()) return result;
3340
3341 Top::set_context(Context::cast(result));
3342
kasper.lund7276f142008-07-30 08:49:36 +00003343 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003344}
3345
3346
3347static Object* Runtime_LookupContext(Arguments args) {
3348 HandleScope scope;
3349 ASSERT(args.length() == 2);
3350
3351 CONVERT_ARG_CHECKED(Context, context, 0);
3352 CONVERT_ARG_CHECKED(String, name, 1);
3353
3354 int index;
3355 PropertyAttributes attributes;
3356 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003357 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358 context->Lookup(name, flags, &index, &attributes);
3359
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003360 if (index < 0 && !holder.is_null()) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003361 ASSERT(holder->IsJSObject());
3362 return *holder;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003363 }
3364
3365 // No intermediate context found. Use global object by default.
3366 return Top::context()->global();
3367}
3368
3369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003370// A mechanism to return pairs of Object*'s. This is somewhat
3371// compiler-dependent as it assumes that a 64-bit value (a long long)
3372// is returned via two registers (edx:eax on ia32). Both the ia32 and
3373// arm platform support this; it is mostly an issue of "coaxing" the
3374// compiler to do the right thing.
3375//
3376// TODO(1236026): This is a non-portable hack that should be removed.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003377typedef uint64_t ObjectPair;
3378static inline ObjectPair MakePair(Object* x, Object* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003379 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003380 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003381}
3382
3383
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003384static inline Object* Unhole(Object* x, PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003385 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
3386 USE(attributes);
3387 return x->IsTheHole() ? Heap::undefined_value() : x;
3388}
3389
3390
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003391static JSObject* ComputeReceiverForNonGlobal(JSObject* holder) {
3392 ASSERT(!holder->IsGlobalObject());
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003393 Context* top = Top::context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003394 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003395 JSFunction* context_extension_function =
3396 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003397 // If the holder isn't a context extension object, we just return it
3398 // as the receiver. This allows arguments objects to be used as
3399 // receivers, but only if they are put in the context scope chain
3400 // explicitly via a with-statement.
3401 Object* constructor = holder->map()->constructor();
3402 if (constructor != context_extension_function) return holder;
3403 // Fall back to using the global object as the receiver if the
3404 // property turns out to be a local variable allocated in a context
3405 // extension object - introduced via eval.
3406 return top->global()->global_receiver();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003407}
3408
3409
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003410static ObjectPair LoadContextSlotHelper(Arguments args, bool throw_error) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003411 HandleScope scope;
3412 ASSERT(args.length() == 2);
3413
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003414 if (!args[0]->IsContext() || !args[1]->IsString()) {
3415 return MakePair(IllegalOperation(), NULL);
3416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003417 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003418 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003419
3420 int index;
3421 PropertyAttributes attributes;
3422 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003423 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 context->Lookup(name, flags, &index, &attributes);
3425
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003426 // If the index is non-negative, the slot has been found in a local
3427 // variable or a parameter. Read it from the context object or the
3428 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003430 // If the "property" we were looking for is a local variable or an
3431 // argument in a context, the receiver is the global object; see
3432 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
3433 JSObject* receiver = Top::context()->global()->global_receiver();
3434 Object* value = (holder->IsContext())
3435 ? Context::cast(*holder)->get(index)
3436 : JSObject::cast(*holder)->GetElement(index);
3437 return MakePair(Unhole(value, attributes), receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438 }
3439
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003440 // If the holder is found, we read the property from it.
3441 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00003442 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003443 JSObject* object = JSObject::cast(*holder);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003444 JSObject* receiver = (object->IsGlobalObject())
3445 ? GlobalObject::cast(object)->global_receiver()
3446 : ComputeReceiverForNonGlobal(object);
3447 // No need to unhole the value here. This is taken care of by the
3448 // GetProperty function.
3449 Object* value = object->GetProperty(*name);
3450 return MakePair(value, receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003451 }
3452
3453 if (throw_error) {
3454 // The property doesn't exist - throw exception.
3455 Handle<Object> reference_error =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003456 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003457 return MakePair(Top::Throw(*reference_error), NULL);
3458 } else {
3459 // The property doesn't exist - return undefined
3460 return MakePair(Heap::undefined_value(), Heap::undefined_value());
3461 }
3462}
3463
3464
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003465static ObjectPair Runtime_LoadContextSlot(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466 return LoadContextSlotHelper(args, true);
3467}
3468
3469
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003470static ObjectPair Runtime_LoadContextSlotNoReferenceError(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471 return LoadContextSlotHelper(args, false);
3472}
3473
3474
3475static Object* Runtime_StoreContextSlot(Arguments args) {
3476 HandleScope scope;
3477 ASSERT(args.length() == 3);
3478
3479 Handle<Object> value(args[0]);
3480 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003481 CONVERT_ARG_CHECKED(String, name, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003482
3483 int index;
3484 PropertyAttributes attributes;
3485 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003486 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003487 context->Lookup(name, flags, &index, &attributes);
3488
3489 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003490 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003491 // Ignore if read_only variable.
3492 if ((attributes & READ_ONLY) == 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003493 Handle<Context>::cast(holder)->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003494 }
3495 } else {
3496 ASSERT((attributes & READ_ONLY) == 0);
3497 Object* result =
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003498 Handle<JSObject>::cast(holder)->SetElement(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003499 USE(result);
3500 ASSERT(!result->IsFailure());
3501 }
3502 return *value;
3503 }
3504
3505 // Slow case: The property is not in a FixedArray context.
3506 // It is either in an JSObject extension context or it was not found.
3507 Handle<JSObject> context_ext;
3508
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003509 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003510 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003511 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003512 } else {
3513 // The property was not found. It needs to be stored in the global context.
3514 ASSERT(attributes == ABSENT);
3515 attributes = NONE;
3516 context_ext = Handle<JSObject>(Top::context()->global());
3517 }
3518
3519 // Set the property, but ignore if read_only variable.
3520 if ((attributes & READ_ONLY) == 0) {
3521 Handle<Object> set = SetProperty(context_ext, name, value, attributes);
3522 if (set.is_null()) {
3523 // Failure::Exception is converted to a null handle in the
3524 // handle-based methods such as SetProperty. We therefore need
3525 // to convert null handles back to exceptions.
3526 ASSERT(Top::has_pending_exception());
3527 return Failure::Exception();
3528 }
3529 }
3530 return *value;
3531}
3532
3533
3534static Object* Runtime_Throw(Arguments args) {
3535 HandleScope scope;
3536 ASSERT(args.length() == 1);
3537
3538 return Top::Throw(args[0]);
3539}
3540
3541
3542static Object* Runtime_ReThrow(Arguments args) {
3543 HandleScope scope;
3544 ASSERT(args.length() == 1);
3545
3546 return Top::ReThrow(args[0]);
3547}
3548
3549
3550static Object* Runtime_ThrowReferenceError(Arguments args) {
3551 HandleScope scope;
3552 ASSERT(args.length() == 1);
3553
3554 Handle<Object> name(args[0]);
3555 Handle<Object> reference_error =
3556 Factory::NewReferenceError("not_defined", HandleVector(&name, 1));
3557 return Top::Throw(*reference_error);
3558}
3559
3560
3561static Object* Runtime_StackOverflow(Arguments args) {
3562 NoHandleAllocation na;
3563 return Top::StackOverflow();
3564}
3565
3566
3567static Object* RuntimePreempt(Arguments args) {
3568 // Clear the preempt request flag.
3569 StackGuard::Continue(PREEMPT);
3570
3571 ContextSwitcher::PreemptionReceived();
3572
3573 {
3574 v8::Unlocker unlocker;
3575 Thread::YieldCPU();
3576 }
3577
3578 return Heap::undefined_value();
3579}
3580
3581
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003582static Object* DebugBreakHelper() {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003583 // Just continue if breaks are disabled.
3584 if (Debug::disable_break()) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003585 return Heap::undefined_value();
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003586 }
3587
kasper.lund7276f142008-07-30 08:49:36 +00003588 // Don't break in system functions. If the current function is
3589 // either in the builtins object of some context or is in the debug
3590 // context just return with the debug break stack guard active.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 JavaScriptFrameIterator it;
3592 JavaScriptFrame* frame = it.frame();
3593 Object* fun = frame->function();
3594 if (fun->IsJSFunction()) {
3595 GlobalObject* global = JSFunction::cast(fun)->context()->global();
3596 if (global->IsJSBuiltinsObject() || Debug::IsDebugGlobal(global)) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003597 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 }
3599 }
3600
3601 // Clear the debug request flag.
3602 StackGuard::Continue(DEBUGBREAK);
3603
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003604 HandleScope scope;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003605 // Enter the debugger. Just continue if we fail to enter the debugger.
3606 EnterDebugger debugger;
3607 if (debugger.FailedToEnter()) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003608 return Heap::undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003609 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003610
kasper.lund7276f142008-07-30 08:49:36 +00003611 // Notify the debug event listeners.
3612 Debugger::OnDebugBreak(Factory::undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003613
3614 // Return to continue execution.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003615 return Heap::undefined_value();
3616}
3617
3618
3619static Object* Runtime_DebugBreak(Arguments args) {
3620 ASSERT(args.length() == 0);
3621 return DebugBreakHelper();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622}
3623
3624
3625static Object* Runtime_StackGuard(Arguments args) {
3626 ASSERT(args.length() == 1);
3627
3628 // First check if this is a real stack overflow.
3629 if (StackGuard::IsStackOverflow()) return Runtime_StackOverflow(args);
3630
3631 // If not real stack overflow the stack guard was used to interrupt
3632 // execution for another purpose.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003633 if (StackGuard::IsDebugBreak()) DebugBreakHelper();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003634 if (StackGuard::IsPreempted()) RuntimePreempt(args);
3635 if (StackGuard::IsInterrupted()) {
3636 // interrupt
3637 StackGuard::Continue(INTERRUPT);
3638 return Top::StackOverflow();
3639 }
3640 return Heap::undefined_value();
3641}
3642
3643
3644// NOTE: These PrintXXX functions are defined for all builds (not just
3645// DEBUG builds) because we may want to be able to trace function
3646// calls in all modes.
3647static void PrintString(String* str) {
3648 // not uncommon to have empty strings
3649 if (str->length() > 0) {
3650 SmartPointer<char> s =
3651 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
3652 PrintF("%s", *s);
3653 }
3654}
3655
3656
3657static void PrintObject(Object* obj) {
3658 if (obj->IsSmi()) {
3659 PrintF("%d", Smi::cast(obj)->value());
3660 } else if (obj->IsString() || obj->IsSymbol()) {
3661 PrintString(String::cast(obj));
3662 } else if (obj->IsNumber()) {
3663 PrintF("%g", obj->Number());
3664 } else if (obj->IsFailure()) {
3665 PrintF("<failure>");
3666 } else if (obj->IsUndefined()) {
3667 PrintF("<undefined>");
3668 } else if (obj->IsNull()) {
3669 PrintF("<null>");
3670 } else if (obj->IsTrue()) {
3671 PrintF("<true>");
3672 } else if (obj->IsFalse()) {
3673 PrintF("<false>");
3674 } else {
3675 PrintF("%p", obj);
3676 }
3677}
3678
3679
3680static int StackSize() {
3681 int n = 0;
3682 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
3683 return n;
3684}
3685
3686
3687static void PrintTransition(Object* result) {
3688 // indentation
3689 { const int nmax = 80;
3690 int n = StackSize();
3691 if (n <= nmax)
3692 PrintF("%4d:%*s", n, n, "");
3693 else
3694 PrintF("%4d:%*s", n, nmax, "...");
3695 }
3696
3697 if (result == NULL) {
3698 // constructor calls
3699 JavaScriptFrameIterator it;
3700 JavaScriptFrame* frame = it.frame();
3701 if (frame->IsConstructor()) PrintF("new ");
3702 // function name
3703 Object* fun = frame->function();
3704 if (fun->IsJSFunction()) {
3705 PrintObject(JSFunction::cast(fun)->shared()->name());
3706 } else {
3707 PrintObject(fun);
3708 }
3709 // function arguments
3710 // (we are intentionally only printing the actually
3711 // supplied parameters, not all parameters required)
3712 PrintF("(this=");
3713 PrintObject(frame->receiver());
3714 const int length = frame->GetProvidedParametersCount();
3715 for (int i = 0; i < length; i++) {
3716 PrintF(", ");
3717 PrintObject(frame->GetParameter(i));
3718 }
3719 PrintF(") {\n");
3720
3721 } else {
3722 // function result
3723 PrintF("} -> ");
3724 PrintObject(result);
3725 PrintF("\n");
3726 }
3727}
3728
3729
3730static Object* Runtime_TraceEnter(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003731 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003732 NoHandleAllocation ha;
3733 PrintTransition(NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003734 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003735}
3736
3737
3738static Object* Runtime_TraceExit(Arguments args) {
3739 NoHandleAllocation ha;
3740 PrintTransition(args[0]);
3741 return args[0]; // return TOS
3742}
3743
3744
3745static Object* Runtime_DebugPrint(Arguments args) {
3746 NoHandleAllocation ha;
3747 ASSERT(args.length() == 1);
3748
3749#ifdef DEBUG
3750 if (args[0]->IsString()) {
3751 // If we have a string, assume it's a code "marker"
3752 // and print some interesting cpu debugging info.
3753 JavaScriptFrameIterator it;
3754 JavaScriptFrame* frame = it.frame();
3755 PrintF("fp = %p, sp = %p, pp = %p: ",
3756 frame->fp(), frame->sp(), frame->pp());
3757 } else {
3758 PrintF("DebugPrint: ");
3759 }
3760 args[0]->Print();
3761#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003762 // ShortPrint is available in release mode. Print is not.
3763 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764#endif
3765 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00003766 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767
3768 return args[0]; // return TOS
3769}
3770
3771
3772static Object* Runtime_DebugTrace(Arguments args) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003773 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774 NoHandleAllocation ha;
3775 Top::PrintStack();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003776 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777}
3778
3779
mads.s.ager31e71382008-08-13 09:32:07 +00003780static Object* Runtime_DateCurrentTime(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003781 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003782 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003783
3784 // According to ECMA-262, section 15.9.1, page 117, the precision of
3785 // the number in a Date object representing a particular instant in
3786 // time is milliseconds. Therefore, we floor the result of getting
3787 // the OS time.
3788 double millis = floor(OS::TimeCurrentMillis());
3789 return Heap::NumberFromDouble(millis);
3790}
3791
3792
3793static Object* Runtime_DateParseString(Arguments args) {
3794 HandleScope scope;
3795 ASSERT(args.length() == 1);
3796
3797 CONVERT_CHECKED(String, string_object, args[0]);
3798
3799 Handle<String> str(string_object);
3800 Handle<FixedArray> output = Factory::NewFixedArray(DateParser::OUTPUT_SIZE);
3801 if (DateParser::Parse(*str, *output)) {
3802 return *Factory::NewJSArrayWithElements(output);
3803 } else {
3804 return *Factory::null_value();
3805 }
3806}
3807
3808
3809static Object* Runtime_DateLocalTimezone(Arguments args) {
3810 NoHandleAllocation ha;
3811 ASSERT(args.length() == 1);
3812
3813 CONVERT_DOUBLE_CHECKED(x, args[0]);
3814 char* zone = OS::LocalTimezone(x);
3815 return Heap::AllocateStringFromUtf8(CStrVector(zone));
3816}
3817
3818
3819static Object* Runtime_DateLocalTimeOffset(Arguments args) {
3820 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00003821 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003822
3823 return Heap::NumberFromDouble(OS::LocalTimeOffset());
3824}
3825
3826
3827static Object* Runtime_DateDaylightSavingsOffset(Arguments args) {
3828 NoHandleAllocation ha;
3829 ASSERT(args.length() == 1);
3830
3831 CONVERT_DOUBLE_CHECKED(x, args[0]);
3832 return Heap::NumberFromDouble(OS::DaylightSavingsOffset(x));
3833}
3834
3835
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003836static Object* Runtime_NumberIsFinite(Arguments args) {
3837 NoHandleAllocation ha;
3838 ASSERT(args.length() == 1);
3839
3840 CONVERT_DOUBLE_CHECKED(value, args[0]);
3841 Object* result;
3842 if (isnan(value) || (fpclassify(value) == FP_INFINITE)) {
3843 result = Heap::false_value();
3844 } else {
3845 result = Heap::true_value();
3846 }
3847 return result;
3848}
3849
3850
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003851static Object* EvalContext() {
3852 // The topmost JS frame belongs to the eval function which called
3853 // the CompileString runtime function. We need to unwind one level
3854 // to get to the caller of eval.
3855 StackFrameLocator locator;
3856 JavaScriptFrame* frame = locator.FindJavaScriptFrame(1);
3857
kasper.lund44510672008-07-25 07:37:58 +00003858 // TODO(900055): Right now we check if the caller of eval() supports
3859 // eval to determine if it's an aliased eval or not. This may not be
3860 // entirely correct in the unlikely case where a function uses both
3861 // aliased and direct eval calls.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003862 HandleScope scope;
3863 if (!ScopeInfo<>::SupportsEval(frame->FindCode())) {
kasper.lund44510672008-07-25 07:37:58 +00003864 // Aliased eval: Evaluate in the global context of the eval
3865 // function to support aliased, cross environment evals.
3866 return *Top::global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003867 }
3868
3869 // Fetch the caller context from the frame.
3870 Handle<Context> caller(Context::cast(frame->context()));
3871
3872 // Check for eval() invocations that cross environments. Use the
3873 // context from the stack if evaluating in current environment.
3874 Handle<Context> target = Top::global_context();
3875 if (caller->global_context() == *target) return *caller;
3876
3877 // Compute a function closure that captures the calling context. We
3878 // need a function that has trivial scope info, since it is only
3879 // used to hold the context chain together.
3880 Handle<JSFunction> closure = Factory::NewFunction(Factory::empty_symbol(),
3881 Factory::undefined_value());
3882 closure->set_context(*caller);
3883
3884 // Create a new adaptor context that has the target environment as
3885 // the extension object. This enables the evaluated code to see both
3886 // the current context with locals and everything and to see global
3887 // variables declared in the target global object. Furthermore, any
3888 // properties introduced with 'var' will be added to the target
3889 // global object because it is the extension object.
3890 Handle<Context> adaptor =
3891 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, closure);
3892 adaptor->set_extension(target->global());
3893 return *adaptor;
3894}
3895
3896
3897static Object* Runtime_EvalReceiver(Arguments args) {
3898 StackFrameLocator locator;
3899 return locator.FindJavaScriptFrame(1)->receiver();
3900}
3901
3902
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003903static Object* Runtime_GlobalReceiver(Arguments args) {
3904 ASSERT(args.length() == 1);
3905 Object* global = args[0];
3906 if (!global->IsJSGlobalObject()) return Heap::null_value();
3907 return JSGlobalObject::cast(global)->global_receiver();
3908}
3909
3910
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003911static Object* Runtime_CompileString(Arguments args) {
3912 HandleScope scope;
ager@chromium.org236ad962008-09-25 09:45:57 +00003913 ASSERT(args.length() == 3);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003914 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org236ad962008-09-25 09:45:57 +00003915 CONVERT_ARG_CHECKED(Smi, line_offset, 1);
3916 bool contextual = args[2]->IsTrue();
3917 RUNTIME_ASSERT(contextual || args[2]->IsFalse());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003918
3919 // Compute the eval context.
3920 Handle<Context> context;
3921 if (contextual) {
3922 // Get eval context. May not be available if we are calling eval
3923 // through an alias, and the corresponding frame doesn't have a
3924 // proper eval context set up.
3925 Object* eval_context = EvalContext();
3926 if (eval_context->IsFailure()) return eval_context;
3927 context = Handle<Context>(Context::cast(eval_context));
3928 } else {
3929 context = Handle<Context>(Top::context()->global_context());
3930 }
3931
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003932
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003933 // Compile source string.
3934 bool is_global = context->IsGlobalContext();
3935 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00003936 Compiler::CompileEval(source, line_offset->value(), is_global);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003937 if (boilerplate.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 Handle<JSFunction> fun =
3939 Factory::NewFunctionFromBoilerplate(boilerplate, context);
3940 return *fun;
3941}
3942
3943
3944static Object* Runtime_CompileScript(Arguments args) {
3945 HandleScope scope;
3946 ASSERT(args.length() == 4);
3947
3948 CONVERT_ARG_CHECKED(String, source, 0);
3949 CONVERT_ARG_CHECKED(String, script, 1);
3950 CONVERT_CHECKED(Smi, line_attrs, args[2]);
3951 int line = line_attrs->value();
3952 CONVERT_CHECKED(Smi, col_attrs, args[3]);
3953 int col = col_attrs->value();
3954 Handle<JSFunction> boilerplate =
3955 Compiler::Compile(source, script, line, col, NULL, NULL);
3956 if (boilerplate.is_null()) return Failure::Exception();
3957 Handle<JSFunction> fun =
3958 Factory::NewFunctionFromBoilerplate(boilerplate,
3959 Handle<Context>(Top::context()));
3960 return *fun;
3961}
3962
3963
3964static Object* Runtime_SetNewFunctionAttributes(Arguments args) {
3965 // This utility adjusts the property attributes for newly created Function
3966 // object ("new Function(...)") by changing the map.
3967 // All it does is changing the prototype property to enumerable
3968 // as specified in ECMA262, 15.3.5.2.
3969 HandleScope scope;
3970 ASSERT(args.length() == 1);
3971 CONVERT_ARG_CHECKED(JSFunction, func, 0);
3972 ASSERT(func->map()->instance_type() ==
3973 Top::function_instance_map()->instance_type());
3974 ASSERT(func->map()->instance_size() ==
3975 Top::function_instance_map()->instance_size());
3976 func->set_map(*Top::function_instance_map());
3977 return *func;
3978}
3979
3980
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003981// Push an array unto an array of arrays if it is not already in the
3982// array. Returns true if the element was pushed on the stack and
3983// false otherwise.
3984static Object* Runtime_PushIfAbsent(Arguments args) {
3985 ASSERT(args.length() == 2);
3986 CONVERT_CHECKED(JSArray, array, args[0]);
3987 CONVERT_CHECKED(JSArray, element, args[1]);
3988 RUNTIME_ASSERT(array->HasFastElements());
3989 int length = Smi::cast(array->length())->value();
3990 FixedArray* elements = FixedArray::cast(array->elements());
3991 for (int i = 0; i < length; i++) {
3992 if (elements->get(i) == element) return Heap::false_value();
3993 }
3994 Object* obj = array->SetFastElement(length, element);
3995 if (obj->IsFailure()) return obj;
3996 return Heap::true_value();
3997}
3998
3999
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004000/**
4001 * A simple visitor visits every element of Array's.
4002 * The backend storage can be a fixed array for fast elements case,
4003 * or a dictionary for sparse array. Since Dictionary is a subtype
4004 * of FixedArray, the class can be used by both fast and slow cases.
4005 * The second parameter of the constructor, fast_elements, specifies
4006 * whether the storage is a FixedArray or Dictionary.
4007 *
4008 * An index limit is used to deal with the situation that a result array
4009 * length overflows 32-bit non-negative integer.
4010 */
4011class ArrayConcatVisitor {
4012 public:
4013 ArrayConcatVisitor(Handle<FixedArray> storage,
4014 uint32_t index_limit,
4015 bool fast_elements) :
4016 storage_(storage), index_limit_(index_limit),
4017 fast_elements_(fast_elements), index_offset_(0) { }
4018
4019 void visit(uint32_t i, Handle<Object> elm) {
4020 uint32_t index = i + index_offset_;
4021 if (index >= index_limit_) return;
4022
4023 if (fast_elements_) {
4024 ASSERT(index < static_cast<uint32_t>(storage_->length()));
4025 storage_->set(index, *elm);
4026
4027 } else {
4028 Handle<Dictionary> dict = Handle<Dictionary>::cast(storage_);
4029 Handle<Dictionary> result =
4030 Factory::DictionaryAtNumberPut(dict, index, elm);
4031 if (!result.is_identical_to(dict))
4032 storage_ = result;
4033 }
4034 }
4035
4036 void increase_index_offset(uint32_t delta) {
4037 index_offset_ += delta;
4038 }
4039
4040 private:
4041 Handle<FixedArray> storage_;
4042 uint32_t index_limit_;
4043 bool fast_elements_;
4044 uint32_t index_offset_;
4045};
4046
4047
4048/**
4049 * A helper function that visits elements of a JSObject. Only elements
4050 * whose index between 0 and range (exclusive) are visited.
4051 *
4052 * If the third parameter, visitor, is not NULL, the visitor is called
4053 * with parameters, 'visitor_index_offset + element index' and the element.
4054 *
4055 * It returns the number of visisted elements.
4056 */
4057static uint32_t IterateElements(Handle<JSObject> receiver,
4058 uint32_t range,
4059 ArrayConcatVisitor* visitor) {
4060 uint32_t num_of_elements = 0;
4061
4062 if (receiver->HasFastElements()) {
4063 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
4064 uint32_t len = elements->length();
4065 if (range < len) len = range;
4066
4067 for (uint32_t j = 0; j < len; j++) {
4068 Handle<Object> e(elements->get(j));
4069 if (!e->IsTheHole()) {
4070 num_of_elements++;
4071 if (visitor)
4072 visitor->visit(j, e);
4073 }
4074 }
4075
4076 } else {
4077 Handle<Dictionary> dict(receiver->element_dictionary());
4078 uint32_t capacity = dict->Capacity();
4079 for (uint32_t j = 0; j < capacity; j++) {
4080 Handle<Object> k(dict->KeyAt(j));
4081 if (dict->IsKey(*k)) {
4082 ASSERT(k->IsNumber());
4083 uint32_t index = static_cast<uint32_t>(k->Number());
4084 if (index < range) {
4085 num_of_elements++;
4086 if (visitor) {
4087 visitor->visit(index,
4088 Handle<Object>(dict->ValueAt(j)));
4089 }
4090 }
4091 }
4092 }
4093 }
4094
4095 return num_of_elements;
4096}
4097
4098
4099/**
4100 * A helper function that visits elements of an Array object, and elements
4101 * on its prototypes.
4102 *
4103 * Elements on prototypes are visited first, and only elements whose indices
4104 * less than Array length are visited.
4105 *
4106 * If a ArrayConcatVisitor object is given, the visitor is called with
4107 * parameters, element's index + visitor_index_offset and the element.
4108 */
4109static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
4110 ArrayConcatVisitor* visitor) {
4111 uint32_t range = static_cast<uint32_t>(array->length()->Number());
4112 Handle<Object> obj = array;
4113
4114 static const int kEstimatedPrototypes = 3;
4115 List< Handle<JSObject> > objects(kEstimatedPrototypes);
4116
4117 // Visit prototype first. If an element on the prototype is shadowed by
4118 // the inheritor using the same index, the ArrayConcatVisitor visits
4119 // the prototype element before the shadowing element.
4120 // The visitor can simply overwrite the old value by new value using
4121 // the same index. This follows Array::concat semantics.
4122 while (!obj->IsNull()) {
4123 objects.Add(Handle<JSObject>::cast(obj));
4124 obj = Handle<Object>(obj->GetPrototype());
4125 }
4126
4127 uint32_t nof_elements = 0;
4128 for (int i = objects.length() - 1; i >= 0; i--) {
4129 Handle<JSObject> obj = objects[i];
4130 nof_elements +=
4131 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
4132 }
4133
4134 return nof_elements;
4135}
4136
4137
4138/**
4139 * A helper function of Runtime_ArrayConcat.
4140 *
4141 * The first argument is an Array of arrays and objects. It is the
4142 * same as the arguments array of Array::concat JS function.
4143 *
4144 * If an argument is an Array object, the function visits array
4145 * elements. If an argument is not an Array object, the function
4146 * visits the object as if it is an one-element array.
4147 *
4148 * If the result array index overflows 32-bit integer, the rounded
4149 * non-negative number is used as new length. For example, if one
4150 * array length is 2^32 - 1, second array length is 1, the
4151 * concatenated array length is 0.
4152 */
4153static uint32_t IterateArguments(Handle<JSArray> arguments,
4154 ArrayConcatVisitor* visitor) {
4155 uint32_t visited_elements = 0;
4156 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
4157
4158 for (uint32_t i = 0; i < num_of_args; i++) {
4159 Handle<Object> obj(arguments->GetElement(i));
4160 if (obj->IsJSArray()) {
4161 Handle<JSArray> array = Handle<JSArray>::cast(obj);
4162 uint32_t len = static_cast<uint32_t>(array->length()->Number());
4163 uint32_t nof_elements =
4164 IterateArrayAndPrototypeElements(array, visitor);
4165 // Total elements of array and its prototype chain can be more than
4166 // the array length, but ArrayConcat can only concatenate at most
4167 // the array length number of elements.
4168 visited_elements += (nof_elements > len) ? len : nof_elements;
4169 if (visitor) visitor->increase_index_offset(len);
4170
4171 } else {
4172 if (visitor) {
4173 visitor->visit(0, obj);
4174 visitor->increase_index_offset(1);
4175 }
4176 visited_elements++;
4177 }
4178 }
4179 return visited_elements;
4180}
4181
4182
4183/**
4184 * Array::concat implementation.
4185 * See ECMAScript 262, 15.4.4.4.
4186 */
4187static Object* Runtime_ArrayConcat(Arguments args) {
4188 ASSERT(args.length() == 1);
4189 HandleScope handle_scope;
4190
4191 CONVERT_CHECKED(JSArray, arg_arrays, args[0]);
4192 Handle<JSArray> arguments(arg_arrays);
4193
4194 // Pass 1: estimate the number of elements of the result
4195 // (it could be more than real numbers if prototype has elements).
4196 uint32_t result_length = 0;
4197 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
4198
4199 { AssertNoAllocation nogc;
4200 for (uint32_t i = 0; i < num_of_args; i++) {
4201 Object* obj = arguments->GetElement(i);
4202 if (obj->IsJSArray()) {
4203 result_length +=
4204 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number());
4205 } else {
4206 result_length++;
4207 }
4208 }
4209 }
4210
4211 // Allocate an empty array, will set length and content later.
4212 Handle<JSArray> result = Factory::NewJSArray(0);
4213
4214 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL);
4215 // If estimated number of elements is more than half of length, a
4216 // fixed array (fast case) is more time and space-efficient than a
4217 // dictionary.
4218 bool fast_case = (estimate_nof_elements * 2) >= result_length;
4219
4220 Handle<FixedArray> storage;
4221 if (fast_case) {
4222 // The backing storage array must have non-existing elements to
4223 // preserve holes across concat operations.
4224 storage = Factory::NewFixedArrayWithHoles(result_length);
4225
4226 } else {
4227 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
4228 uint32_t at_least_space_for = estimate_nof_elements +
4229 (estimate_nof_elements >> 2);
4230 storage = Handle<FixedArray>::cast(
4231 Factory::NewDictionary(at_least_space_for));
4232 }
4233
4234 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length));
4235
4236 ArrayConcatVisitor visitor(storage, result_length, fast_case);
4237
4238 IterateArguments(arguments, &visitor);
4239
4240 result->set_length(*len);
4241 result->set_elements(*storage);
4242
4243 return *result;
4244}
4245
4246
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004247// This will not allocate (flatten the string), but it may run
4248// very slowly for very deeply nested ConsStrings. For debugging use only.
4249static Object* Runtime_GlobalPrint(Arguments args) {
4250 NoHandleAllocation ha;
4251 ASSERT(args.length() == 1);
4252
4253 CONVERT_CHECKED(String, string, args[0]);
4254 StringInputBuffer buffer(string);
4255 while (buffer.has_more()) {
4256 uint16_t character = buffer.GetNext();
4257 PrintF("%c", character);
4258 }
4259 return string;
4260}
4261
4262
4263static Object* Runtime_RemoveArrayHoles(Arguments args) {
4264 ASSERT(args.length() == 1);
4265 // Ignore the case if this is not a JSArray.
4266 if (!args[0]->IsJSArray()) return args[0];
4267 return JSArray::cast(args[0])->RemoveHoles();
4268}
4269
4270
4271// Move contents of argument 0 (an array) to argument 1 (an array)
4272static Object* Runtime_MoveArrayContents(Arguments args) {
4273 ASSERT(args.length() == 2);
4274 CONVERT_CHECKED(JSArray, from, args[0]);
4275 CONVERT_CHECKED(JSArray, to, args[1]);
4276 to->SetContent(FixedArray::cast(from->elements()));
4277 to->set_length(from->length());
4278 from->SetContent(Heap::empty_fixed_array());
4279 from->set_length(0);
4280 return to;
4281}
4282
4283
4284// How many elements does this array have?
4285static Object* Runtime_EstimateNumberOfElements(Arguments args) {
4286 ASSERT(args.length() == 1);
4287 CONVERT_CHECKED(JSArray, array, args[0]);
4288 HeapObject* elements = array->elements();
4289 if (elements->IsDictionary()) {
4290 return Smi::FromInt(Dictionary::cast(elements)->NumberOfElements());
4291 } else {
4292 return array->length();
4293 }
4294}
4295
4296
4297// Returns an array that tells you where in the [0, length) interval an array
4298// might have elements. Can either return keys or intervals. Keys can have
4299// gaps in (undefined). Intervals can also span over some undefined keys.
4300static Object* Runtime_GetArrayKeys(Arguments args) {
4301 ASSERT(args.length() == 2);
4302 HandleScope scope;
4303 CONVERT_CHECKED(JSArray, raw_array, args[0]);
4304 Handle<JSArray> array(raw_array);
4305 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004306 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004307 // Create an array and get all the keys into it, then remove all the
4308 // keys that are not integers in the range 0 to length-1.
4309 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array);
4310 int keys_length = keys->length();
4311 for (int i = 0; i < keys_length; i++) {
4312 Object* key = keys->get(i);
4313 uint32_t index;
4314 if (!Array::IndexFromObject(key, &index) || index >= length) {
4315 // Zap invalid keys.
4316 keys->set_undefined(i);
4317 }
4318 }
4319 return *Factory::NewJSArrayWithElements(keys);
4320 } else {
4321 Handle<FixedArray> single_interval = Factory::NewFixedArray(2);
4322 // -1 means start of array.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004323 single_interval->set(0,
4324 Smi::FromInt(-1),
4325 SKIP_WRITE_BARRIER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004326 Handle<Object> length_object =
4327 Factory::NewNumber(static_cast<double>(length));
4328 single_interval->set(1, *length_object);
4329 return *Factory::NewJSArrayWithElements(single_interval);
4330 }
4331}
4332
4333
4334// DefineAccessor takes an optional final argument which is the
4335// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
4336// to the way accessors are implemented, it is set for both the getter
4337// and setter on the first call to DefineAccessor and ignored on
4338// subsequent calls.
4339static Object* Runtime_DefineAccessor(Arguments args) {
4340 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
4341 // Compute attributes.
4342 PropertyAttributes attributes = NONE;
4343 if (args.length() == 5) {
4344 CONVERT_CHECKED(Smi, attrs, args[4]);
4345 int value = attrs->value();
4346 // Only attribute bits should be set.
4347 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4348 attributes = static_cast<PropertyAttributes>(value);
4349 }
4350
4351 CONVERT_CHECKED(JSObject, obj, args[0]);
4352 CONVERT_CHECKED(String, name, args[1]);
4353 CONVERT_CHECKED(Smi, flag, args[2]);
4354 CONVERT_CHECKED(JSFunction, fun, args[3]);
4355 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
4356}
4357
4358
4359static Object* Runtime_LookupAccessor(Arguments args) {
4360 ASSERT(args.length() == 3);
4361 CONVERT_CHECKED(JSObject, obj, args[0]);
4362 CONVERT_CHECKED(String, name, args[1]);
4363 CONVERT_CHECKED(Smi, flag, args[2]);
4364 return obj->LookupAccessor(name, flag->value() == 0);
4365}
4366
4367
4368// Helper functions for wrapping and unwrapping stack frame ids.
4369static Smi* WrapFrameId(StackFrame::Id id) {
4370 ASSERT(IsAligned(OffsetFrom(id), 4));
4371 return Smi::FromInt(id >> 2);
4372}
4373
4374
4375static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
4376 return static_cast<StackFrame::Id>(wrapped->value() << 2);
4377}
4378
4379
4380// Adds a JavaScript function as a debug event listener.
4381// args[0]: debug event listener function
4382// args[1]: object supplied during callback
4383static Object* Runtime_AddDebugEventListener(Arguments args) {
4384 ASSERT(args.length() == 2);
4385 // Convert the parameters to API objects to call the API function for adding
4386 // a JavaScript function as debug event listener.
4387 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4388 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
4389 v8::Handle<v8::Value> data(ToApi<v8::Value>(args.at<Object>(0)));
4390 v8::Debug::AddDebugEventListener(fun, data);
4391
4392 return Heap::undefined_value();
4393}
4394
4395
4396// Removes a JavaScript function debug event listener.
4397// args[0]: debug event listener function
4398static Object* Runtime_RemoveDebugEventListener(Arguments args) {
4399 ASSERT(args.length() == 1);
4400 // Convert the parameter to an API object to call the API function for
4401 // removing a JavaScript function debug event listener.
4402 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4403 v8::Handle<v8::Function> fun(ToApi<v8::Function>(raw_fun));
4404 v8::Debug::RemoveDebugEventListener(fun);
4405
4406 return Heap::undefined_value();
4407}
4408
4409
4410static Object* Runtime_Break(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00004411 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004412 StackGuard::DebugBreak();
4413 return Heap::undefined_value();
4414}
4415
4416
4417static Object* DebugLookupResultValue(LookupResult* result) {
4418 Object* value;
4419 switch (result->type()) {
4420 case NORMAL: {
4421 Dictionary* dict =
4422 JSObject::cast(result->holder())->property_dictionary();
4423 value = dict->ValueAt(result->GetDictionaryEntry());
4424 if (value->IsTheHole()) {
4425 return Heap::undefined_value();
4426 }
4427 return value;
4428 }
4429 case FIELD:
4430 value =
4431 JSObject::cast(
ager@chromium.org7c537e22008-10-16 08:43:32 +00004432 result->holder())->FastPropertyAt(result->GetFieldIndex());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004433 if (value->IsTheHole()) {
4434 return Heap::undefined_value();
4435 }
4436 return value;
4437 case CONSTANT_FUNCTION:
4438 return result->GetConstantFunction();
4439 case CALLBACKS:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004441 case MAP_TRANSITION:
4442 case CONSTANT_TRANSITION:
4443 case NULL_DESCRIPTOR:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004444 return Heap::undefined_value();
4445 default:
4446 UNREACHABLE();
4447 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004448 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004449 return Heap::undefined_value();
4450}
4451
4452
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004453static Object* Runtime_DebugGetPropertyDetails(Arguments args) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004454 HandleScope scope;
4455
4456 ASSERT(args.length() == 2);
4457
4458 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4459 CONVERT_ARG_CHECKED(String, name, 1);
4460
4461 // Check if the name is trivially convertible to an index and get the element
4462 // if so.
4463 uint32_t index;
4464 if (name->AsArrayIndex(&index)) {
4465 Handle<FixedArray> details = Factory::NewFixedArray(2);
4466 details->set(0, Runtime::GetElementOrCharAt(obj, index));
4467 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
4468 return *Factory::NewJSArrayWithElements(details);
4469 }
4470
4471 // Perform standard local lookup on the object.
4472 LookupResult result;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004473 obj->Lookup(*name, &result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004474 if (result.IsProperty()) {
4475 Handle<Object> value(DebugLookupResultValue(&result));
4476 Handle<FixedArray> details = Factory::NewFixedArray(2);
4477 details->set(0, *value);
4478 details->set(1, result.GetPropertyDetails().AsSmi());
4479 return *Factory::NewJSArrayWithElements(details);
4480 }
4481 return Heap::undefined_value();
4482}
4483
4484
4485static Object* Runtime_DebugGetProperty(Arguments args) {
4486 HandleScope scope;
4487
4488 ASSERT(args.length() == 2);
4489
4490 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4491 CONVERT_ARG_CHECKED(String, name, 1);
4492
4493 LookupResult result;
4494 obj->Lookup(*name, &result);
4495 if (result.IsProperty()) {
4496 return DebugLookupResultValue(&result);
4497 }
4498 return Heap::undefined_value();
4499}
4500
4501
4502// Return the names of the local named properties.
4503// args[0]: object
4504static Object* Runtime_DebugLocalPropertyNames(Arguments args) {
4505 HandleScope scope;
4506 ASSERT(args.length() == 1);
4507 if (!args[0]->IsJSObject()) {
4508 return Heap::undefined_value();
4509 }
4510 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4511
4512 int n = obj->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4513 Handle<FixedArray> names = Factory::NewFixedArray(n);
4514 obj->GetLocalPropertyNames(*names);
4515 return *Factory::NewJSArrayWithElements(names);
4516}
4517
4518
4519// Return the names of the local indexed properties.
4520// args[0]: object
4521static Object* Runtime_DebugLocalElementNames(Arguments args) {
4522 HandleScope scope;
4523 ASSERT(args.length() == 1);
4524 if (!args[0]->IsJSObject()) {
4525 return Heap::undefined_value();
4526 }
4527 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4528
4529 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
4530 Handle<FixedArray> names = Factory::NewFixedArray(n);
4531 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
4532 return *Factory::NewJSArrayWithElements(names);
4533}
4534
4535
4536// Return the property type calculated from the property details.
4537// args[0]: smi with property details.
4538static Object* Runtime_DebugPropertyTypeFromDetails(Arguments args) {
4539 ASSERT(args.length() == 1);
4540 CONVERT_CHECKED(Smi, details, args[0]);
4541 PropertyType type = PropertyDetails(details).type();
4542 return Smi::FromInt(static_cast<int>(type));
4543}
4544
4545
4546// Return the property attribute calculated from the property details.
4547// args[0]: smi with property details.
4548static Object* Runtime_DebugPropertyAttributesFromDetails(Arguments args) {
4549 ASSERT(args.length() == 1);
4550 CONVERT_CHECKED(Smi, details, args[0]);
4551 PropertyAttributes attributes = PropertyDetails(details).attributes();
4552 return Smi::FromInt(static_cast<int>(attributes));
4553}
4554
4555
4556// Return the property insertion index calculated from the property details.
4557// args[0]: smi with property details.
4558static Object* Runtime_DebugPropertyIndexFromDetails(Arguments args) {
4559 ASSERT(args.length() == 1);
4560 CONVERT_CHECKED(Smi, details, args[0]);
4561 int index = PropertyDetails(details).index();
4562 return Smi::FromInt(index);
4563}
4564
4565
4566// Return information on whether an object has a named or indexed interceptor.
4567// args[0]: object
4568static Object* Runtime_DebugInterceptorInfo(Arguments args) {
4569 HandleScope scope;
4570 ASSERT(args.length() == 1);
4571 if (!args[0]->IsJSObject()) {
4572 return Smi::FromInt(0);
4573 }
4574 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4575
4576 int result = 0;
4577 if (obj->HasNamedInterceptor()) result |= 2;
4578 if (obj->HasIndexedInterceptor()) result |= 1;
4579
4580 return Smi::FromInt(result);
4581}
4582
4583
4584// Return property names from named interceptor.
4585// args[0]: object
4586static Object* Runtime_DebugNamedInterceptorPropertyNames(Arguments args) {
4587 HandleScope scope;
4588 ASSERT(args.length() == 1);
4589 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4590 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4591
4592 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4593 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4594 return Heap::undefined_value();
4595}
4596
4597
4598// Return element names from indexed interceptor.
4599// args[0]: object
4600static Object* Runtime_DebugIndexedInterceptorElementNames(Arguments args) {
4601 HandleScope scope;
4602 ASSERT(args.length() == 1);
4603 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4604 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4605
4606 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4607 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4608 return Heap::undefined_value();
4609}
4610
4611
4612// Return property value from named interceptor.
4613// args[0]: object
4614// args[1]: property name
4615static Object* Runtime_DebugNamedInterceptorPropertyValue(Arguments args) {
4616 HandleScope scope;
4617 ASSERT(args.length() == 2);
4618 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4619 RUNTIME_ASSERT(obj->HasNamedInterceptor());
4620 CONVERT_ARG_CHECKED(String, name, 1);
4621
4622 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004623 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004624}
4625
4626
4627// Return element value from indexed interceptor.
4628// args[0]: object
4629// args[1]: index
4630static Object* Runtime_DebugIndexedInterceptorElementValue(Arguments args) {
4631 HandleScope scope;
4632 ASSERT(args.length() == 2);
4633 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4634 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
4635 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
4636
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004637 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004638}
4639
4640
4641static Object* Runtime_CheckExecutionState(Arguments args) {
4642 ASSERT(args.length() >= 1);
4643 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
4644 // Check that the break id is valid and that there is a valid frame
4645 // where execution is broken.
4646 if (break_id != Top::break_id() ||
4647 Top::break_frame_id() == StackFrame::NO_ID) {
4648 return Top::Throw(Heap::illegal_execution_state_symbol());
4649 }
4650
4651 return Heap::true_value();
4652}
4653
4654
4655static Object* Runtime_GetFrameCount(Arguments args) {
4656 HandleScope scope;
4657 ASSERT(args.length() == 1);
4658
4659 // Check arguments.
4660 Object* result = Runtime_CheckExecutionState(args);
4661 if (result->IsFailure()) return result;
4662
4663 // Count all frames which are relevant to debugging stack trace.
4664 int n = 0;
4665 StackFrame::Id id = Top::break_frame_id();
4666 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) n++;
4667 return Smi::FromInt(n);
4668}
4669
4670
4671static const int kFrameDetailsFrameIdIndex = 0;
4672static const int kFrameDetailsReceiverIndex = 1;
4673static const int kFrameDetailsFunctionIndex = 2;
4674static const int kFrameDetailsArgumentCountIndex = 3;
4675static const int kFrameDetailsLocalCountIndex = 4;
4676static const int kFrameDetailsSourcePositionIndex = 5;
4677static const int kFrameDetailsConstructCallIndex = 6;
4678static const int kFrameDetailsDebuggerFrameIndex = 7;
4679static const int kFrameDetailsFirstDynamicIndex = 8;
4680
4681// Return an array with frame details
4682// args[0]: number: break id
4683// args[1]: number: frame index
4684//
4685// The array returned contains the following information:
4686// 0: Frame id
4687// 1: Receiver
4688// 2: Function
4689// 3: Argument count
4690// 4: Local count
4691// 5: Source position
4692// 6: Constructor call
4693// 7: Debugger frame
4694// Arguments name, value
4695// Locals name, value
4696static Object* Runtime_GetFrameDetails(Arguments args) {
4697 HandleScope scope;
4698 ASSERT(args.length() == 2);
4699
4700 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004701 Object* check = Runtime_CheckExecutionState(args);
4702 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004703 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
4704
4705 // Find the relevant frame with the requested index.
4706 StackFrame::Id id = Top::break_frame_id();
4707 int count = 0;
4708 JavaScriptFrameIterator it(id);
4709 for (; !it.done(); it.Advance()) {
4710 if (count == index) break;
4711 count++;
4712 }
4713 if (it.done()) return Heap::undefined_value();
4714
4715 // Traverse the saved contexts chain to find the active context for the
4716 // selected frame.
4717 SaveContext* save = Top::save_context();
4718 while (save != NULL && reinterpret_cast<Address>(save) < it.frame()->sp()) {
4719 save = save->prev();
4720 }
4721
4722 // Get the frame id.
4723 Handle<Object> frame_id(WrapFrameId(it.frame()->id()));
4724
4725 // Find source position.
4726 int position = it.frame()->FindCode()->SourcePosition(it.frame()->pc());
4727
4728 // Check for constructor frame.
4729 bool constructor = it.frame()->IsConstructor();
4730
4731 // Get code and read scope info from it for local variable information.
4732 Handle<Code> code(it.frame()->FindCode());
4733 ScopeInfo<> info(*code);
4734
4735 // Get the context.
4736 Handle<Context> context(Context::cast(it.frame()->context()));
4737
4738 // Get the locals names and values into a temporary array.
4739 //
4740 // TODO(1240907): Hide compiler-introduced stack variables
4741 // (e.g. .result)? For users of the debugger, they will probably be
4742 // confusing.
4743 Handle<FixedArray> locals = Factory::NewFixedArray(info.NumberOfLocals() * 2);
4744 for (int i = 0; i < info.NumberOfLocals(); i++) {
4745 // Name of the local.
4746 locals->set(i * 2, *info.LocalName(i));
4747
4748 // Fetch the value of the local - either from the stack or from a
4749 // heap-allocated context.
4750 if (i < info.number_of_stack_slots()) {
4751 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
4752 } else {
4753 Handle<String> name = info.LocalName(i);
4754 // Traverse the context chain to the function context as all local
4755 // variables stored in the context will be on the function context.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00004756 while (!context->is_function_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004757 context = Handle<Context>(context->previous());
4758 }
4759 ASSERT(context->is_function_context());
4760 locals->set(i * 2 + 1,
4761 context->get(ScopeInfo<>::ContextSlotIndex(*code, *name,
4762 NULL)));
4763 }
4764 }
4765
4766 // Now advance to the arguments adapter frame (if any). If contains all
4767 // the provided parameters and
4768
4769 // Now advance to the arguments adapter frame (if any). It contains all
4770 // the provided parameters whereas the function frame always have the number
4771 // of arguments matching the functions parameters. The rest of the
4772 // information (except for what is collected above) is the same.
4773 it.AdvanceToArgumentsFrame();
4774
4775 // Find the number of arguments to fill. At least fill the number of
4776 // parameters for the function and fill more if more parameters are provided.
4777 int argument_count = info.number_of_parameters();
4778 if (argument_count < it.frame()->GetProvidedParametersCount()) {
4779 argument_count = it.frame()->GetProvidedParametersCount();
4780 }
4781
4782 // Calculate the size of the result.
4783 int details_size = kFrameDetailsFirstDynamicIndex +
4784 2 * (argument_count + info.NumberOfLocals());
4785 Handle<FixedArray> details = Factory::NewFixedArray(details_size);
4786
4787 // Add the frame id.
4788 details->set(kFrameDetailsFrameIdIndex, *frame_id);
4789
4790 // Add the function (same as in function frame).
4791 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
4792
4793 // Add the arguments count.
4794 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
4795
4796 // Add the locals count
4797 details->set(kFrameDetailsLocalCountIndex,
4798 Smi::FromInt(info.NumberOfLocals()));
4799
4800 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +00004801 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004802 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
4803 } else {
4804 details->set(kFrameDetailsSourcePositionIndex, Heap::undefined_value());
4805 }
4806
4807 // Add the constructor information.
4808 details->set(kFrameDetailsConstructCallIndex, Heap::ToBoolean(constructor));
4809
4810 // Add information on whether this frame is invoked in the debugger context.
4811 details->set(kFrameDetailsDebuggerFrameIndex,
4812 Heap::ToBoolean(*save->context() == *Debug::debug_context()));
4813
4814 // Fill the dynamic part.
4815 int details_index = kFrameDetailsFirstDynamicIndex;
4816
4817 // Add arguments name and value.
4818 for (int i = 0; i < argument_count; i++) {
4819 // Name of the argument.
4820 if (i < info.number_of_parameters()) {
4821 details->set(details_index++, *info.parameter_name(i));
4822 } else {
4823 details->set(details_index++, Heap::undefined_value());
4824 }
4825
4826 // Parameter value.
4827 if (i < it.frame()->GetProvidedParametersCount()) {
4828 details->set(details_index++, it.frame()->GetParameter(i));
4829 } else {
4830 details->set(details_index++, Heap::undefined_value());
4831 }
4832 }
4833
4834 // Add locals name and value from the temporary copy from the function frame.
4835 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
4836 details->set(details_index++, locals->get(i));
4837 }
4838
4839 // Add the receiver (same as in function frame).
4840 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
4841 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
4842 Handle<Object> receiver(it.frame()->receiver());
4843 if (!receiver->IsJSObject()) {
4844 // If the receiver is NOT a JSObject we have hit an optimization
4845 // where a value object is not converted into a wrapped JS objects.
4846 // To hide this optimization from the debugger, we wrap the receiver
4847 // by creating correct wrapper object based on the calling frame's
4848 // global context.
4849 it.Advance();
4850 Handle<Context> calling_frames_global_context(
4851 Context::cast(Context::cast(it.frame()->context())->global_context()));
4852 receiver = Factory::ToObject(receiver, calling_frames_global_context);
4853 }
4854 details->set(kFrameDetailsReceiverIndex, *receiver);
4855
4856 ASSERT_EQ(details_size, details_index);
4857 return *Factory::NewJSArrayWithElements(details);
4858}
4859
4860
4861static Object* Runtime_GetCFrames(Arguments args) {
4862 HandleScope scope;
4863 ASSERT(args.length() == 1);
4864 Object* result = Runtime_CheckExecutionState(args);
4865 if (result->IsFailure()) return result;
4866
4867 static const int kMaxCFramesSize = 200;
4868 OS::StackFrame frames[kMaxCFramesSize];
4869 int frames_count = OS::StackWalk(frames, kMaxCFramesSize);
4870 if (frames_count == OS::kStackWalkError) {
4871 return Heap::undefined_value();
4872 }
4873
4874 Handle<String> address_str = Factory::LookupAsciiSymbol("address");
4875 Handle<String> text_str = Factory::LookupAsciiSymbol("text");
4876 Handle<FixedArray> frames_array = Factory::NewFixedArray(frames_count);
4877 for (int i = 0; i < frames_count; i++) {
4878 Handle<JSObject> frame_value = Factory::NewJSObject(Top::object_function());
4879 frame_value->SetProperty(
4880 *address_str,
4881 *Factory::NewNumberFromInt(reinterpret_cast<int>(frames[i].address)),
4882 NONE);
4883
4884 // Get the stack walk text for this frame.
4885 Handle<String> frame_text;
4886 if (strlen(frames[i].text) > 0) {
4887 Vector<const char> str(frames[i].text, strlen(frames[i].text));
4888 frame_text = Factory::NewStringFromAscii(str);
4889 }
4890
4891 if (!frame_text.is_null()) {
4892 frame_value->SetProperty(*text_str, *frame_text, NONE);
4893 }
4894
4895 frames_array->set(i, *frame_value);
4896 }
4897 return *Factory::NewJSArrayWithElements(frames_array);
4898}
4899
4900
4901static Object* Runtime_GetBreakLocations(Arguments args) {
4902 HandleScope scope;
4903 ASSERT(args.length() == 1);
4904
4905 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4906 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4907 // Find the number of break points
4908 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
4909 if (break_locations->IsUndefined()) return Heap::undefined_value();
4910 // Return array as JS array
4911 return *Factory::NewJSArrayWithElements(
4912 Handle<FixedArray>::cast(break_locations));
4913}
4914
4915
4916// Set a break point in a function
4917// args[0]: function
4918// args[1]: number: break source position (within the function source)
4919// args[2]: number: break point object
4920static Object* Runtime_SetFunctionBreakPoint(Arguments args) {
4921 HandleScope scope;
4922 ASSERT(args.length() == 3);
4923 CONVERT_ARG_CHECKED(JSFunction, raw_fun, 0);
4924 Handle<SharedFunctionInfo> shared(raw_fun->shared());
4925 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
4926 RUNTIME_ASSERT(source_position >= 0);
4927 Handle<Object> break_point_object_arg = args.at<Object>(2);
4928
4929 // Set break point.
4930 Debug::SetBreakPoint(shared, source_position, break_point_object_arg);
4931
4932 return Heap::undefined_value();
4933}
4934
4935
4936static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
4937 int position) {
4938 // Iterate the heap looking for SharedFunctionInfo generated from the
4939 // script. The inner most SharedFunctionInfo containing the source position
4940 // for the requested break point is found.
4941 // NOTE: This might reqire several heap iterations. If the SharedFunctionInfo
4942 // which is found is not compiled it is compiled and the heap is iterated
4943 // again as the compilation might create inner functions from the newly
4944 // compiled function and the actual requested break point might be in one of
4945 // these functions.
4946 bool done = false;
4947 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +00004948 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004949 Handle<SharedFunctionInfo> target;
4950 // The current candidate for the last function in script:
4951 Handle<SharedFunctionInfo> last;
4952 while (!done) {
4953 HeapIterator iterator;
4954 while (iterator.has_next()) {
4955 HeapObject* obj = iterator.next();
4956 ASSERT(obj != NULL);
4957 if (obj->IsSharedFunctionInfo()) {
4958 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
4959 if (shared->script() == *script) {
4960 // If the SharedFunctionInfo found has the requested script data and
4961 // contains the source position it is a candidate.
4962 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +00004963 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004964 start_position = shared->start_position();
4965 }
4966 if (start_position <= position &&
4967 position <= shared->end_position()) {
4968 // If there is no candidate or this function is within the currrent
4969 // candidate this is the new candidate.
4970 if (target.is_null()) {
4971 target_start_position = start_position;
4972 target = shared;
4973 } else {
4974 if (target_start_position < start_position &&
4975 shared->end_position() < target->end_position()) {
4976 target_start_position = start_position;
4977 target = shared;
4978 }
4979 }
4980 }
4981
4982 // Keep track of the last function in the script.
4983 if (last.is_null() ||
4984 shared->end_position() > last->start_position()) {
4985 last = shared;
4986 }
4987 }
4988 }
4989 }
4990
4991 // Make sure some candidate is selected.
4992 if (target.is_null()) {
4993 if (!last.is_null()) {
4994 // Position after the last function - use last.
4995 target = last;
4996 } else {
4997 // Unable to find function - possibly script without any function.
4998 return Heap::undefined_value();
4999 }
5000 }
5001
5002 // If the candidate found is compiled we are done. NOTE: when lazy
5003 // compilation of inner functions is introduced some additional checking
5004 // needs to be done here to compile inner functions.
5005 done = target->is_compiled();
5006 if (!done) {
5007 // If the candidate is not compiled compile it to reveal any inner
5008 // functions which might contain the requested source position.
5009 CompileLazyShared(target, KEEP_EXCEPTION);
5010 }
5011 }
5012
5013 return *target;
5014}
5015
5016
5017// Change the state of a break point in a script. NOTE: Regarding performance
5018// see the NOTE for GetScriptFromScriptData.
5019// args[0]: script to set break point in
5020// args[1]: number: break source position (within the script source)
5021// args[2]: number: break point object
5022static Object* Runtime_SetScriptBreakPoint(Arguments args) {
5023 HandleScope scope;
5024 ASSERT(args.length() == 3);
5025 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
5026 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
5027 RUNTIME_ASSERT(source_position >= 0);
5028 Handle<Object> break_point_object_arg = args.at<Object>(2);
5029
5030 // Get the script from the script wrapper.
5031 RUNTIME_ASSERT(wrapper->value()->IsScript());
5032 Handle<Script> script(Script::cast(wrapper->value()));
5033
5034 Object* result = FindSharedFunctionInfoInScript(script, source_position);
5035 if (!result->IsUndefined()) {
5036 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
5037 // Find position within function. The script position might be before the
5038 // source position of the first function.
5039 int position;
5040 if (shared->start_position() > source_position) {
5041 position = 0;
5042 } else {
5043 position = source_position - shared->start_position();
5044 }
5045 Debug::SetBreakPoint(shared, position, break_point_object_arg);
5046 }
5047 return Heap::undefined_value();
5048}
5049
5050
5051// Clear a break point
5052// args[0]: number: break point object
5053static Object* Runtime_ClearBreakPoint(Arguments args) {
5054 HandleScope scope;
5055 ASSERT(args.length() == 1);
5056 Handle<Object> break_point_object_arg = args.at<Object>(0);
5057
5058 // Clear break point.
5059 Debug::ClearBreakPoint(break_point_object_arg);
5060
5061 return Heap::undefined_value();
5062}
5063
5064
5065// Change the state of break on exceptions
5066// args[0]: boolean indicating uncaught exceptions
5067// args[1]: boolean indicating on/off
5068static Object* Runtime_ChangeBreakOnException(Arguments args) {
5069 HandleScope scope;
5070 ASSERT(args.length() == 2);
5071 ASSERT(args[0]->IsNumber());
5072 ASSERT(args[1]->IsBoolean());
5073
5074 // Update break point state
5075 ExceptionBreakType type =
5076 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
5077 bool enable = args[1]->ToBoolean()->IsTrue();
5078 Debug::ChangeBreakOnException(type, enable);
5079 return Heap::undefined_value();
5080}
5081
5082
5083// Prepare for stepping
5084// args[0]: break id for checking execution state
5085// args[1]: step action from the enumeration StepAction
5086// args[2]: number of times to perform the step
5087static Object* Runtime_PrepareStep(Arguments args) {
5088 HandleScope scope;
5089 ASSERT(args.length() == 3);
5090 // Check arguments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00005091 Object* check = Runtime_CheckExecutionState(args);
5092 if (check->IsFailure()) return check;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
5094 return Top::Throw(Heap::illegal_argument_symbol());
5095 }
5096
5097 // Get the step action and check validity.
5098 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
5099 if (step_action != StepIn &&
5100 step_action != StepNext &&
5101 step_action != StepOut &&
5102 step_action != StepInMin &&
5103 step_action != StepMin) {
5104 return Top::Throw(Heap::illegal_argument_symbol());
5105 }
5106
5107 // Get the number of steps.
5108 int step_count = NumberToInt32(args[2]);
5109 if (step_count < 1) {
5110 return Top::Throw(Heap::illegal_argument_symbol());
5111 }
5112
5113 // Prepare step.
5114 Debug::PrepareStep(static_cast<StepAction>(step_action), step_count);
5115 return Heap::undefined_value();
5116}
5117
5118
5119// Clear all stepping set by PrepareStep.
5120static Object* Runtime_ClearStepping(Arguments args) {
5121 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005122 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005123 Debug::ClearStepping();
5124 return Heap::undefined_value();
5125}
5126
5127
5128// Creates a copy of the with context chain. The copy of the context chain is
5129// is linked to the function context supplied.
5130static Handle<Context> CopyWithContextChain(Handle<Context> context_chain,
5131 Handle<Context> function_context) {
5132 // At the bottom of the chain. Return the function context to link to.
5133 if (context_chain->is_function_context()) {
5134 return function_context;
5135 }
5136
5137 // Recursively copy the with contexts.
5138 Handle<Context> previous(context_chain->previous());
5139 Handle<JSObject> extension(JSObject::cast(context_chain->extension()));
5140 return Factory::NewWithContext(
5141 CopyWithContextChain(function_context, previous), extension);
5142}
5143
5144
5145// Helper function to find or create the arguments object for
5146// Runtime_DebugEvaluate.
5147static Handle<Object> GetArgumentsObject(JavaScriptFrame* frame,
5148 Handle<JSFunction> function,
5149 Handle<Code> code,
5150 const ScopeInfo<>* sinfo,
5151 Handle<Context> function_context) {
5152 // Try to find the value of 'arguments' to pass as parameter. If it is not
5153 // found (that is the debugged function does not reference 'arguments' and
5154 // does not support eval) then create an 'arguments' object.
5155 int index;
5156 if (sinfo->number_of_stack_slots() > 0) {
5157 index = ScopeInfo<>::StackSlotIndex(*code, Heap::arguments_symbol());
5158 if (index != -1) {
5159 return Handle<Object>(frame->GetExpression(index));
5160 }
5161 }
5162
5163 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
5164 index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_symbol(),
5165 NULL);
5166 if (index != -1) {
5167 return Handle<Object>(function_context->get(index));
5168 }
5169 }
5170
5171 const int length = frame->GetProvidedParametersCount();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005172 Handle<JSObject> arguments = Factory::NewArgumentsObject(function, length);
5173 Handle<FixedArray> array = Factory::NewFixedArray(length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005174 WriteBarrierMode mode = array->GetWriteBarrierMode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005175 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00005176 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005177 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005178 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005179 return arguments;
5180}
5181
5182
5183// Evaluate a piece of JavaScript in the context of a stack frame for
5184// debugging. This is acomplished by creating a new context which in its
5185// extension part has all the parameters and locals of the function on the
5186// stack frame. A function which calls eval with the code to evaluate is then
5187// compiled in this context and called in this context. As this context
5188// replaces the context of the function on the stack frame a new (empty)
5189// function is created as well to be used as the closure for the context.
5190// This function and the context acts as replacements for the function on the
5191// stack frame presenting the same view of the values of parameters and
5192// local variables as if the piece of JavaScript was evaluated at the point
5193// where the function on the stack frame is currently stopped.
5194static Object* Runtime_DebugEvaluate(Arguments args) {
5195 HandleScope scope;
5196
5197 // Check the execution state and decode arguments frame and source to be
5198 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005199 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005200 Object* check_result = Runtime_CheckExecutionState(args);
5201 if (check_result->IsFailure()) return check_result;
5202 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
5203 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005204 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
5205
5206 // Handle the processing of break.
5207 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208
5209 // Get the frame where the debugging is performed.
5210 StackFrame::Id id = UnwrapFrameId(wrapped_id);
5211 JavaScriptFrameIterator it(id);
5212 JavaScriptFrame* frame = it.frame();
5213 Handle<JSFunction> function(JSFunction::cast(frame->function()));
5214 Handle<Code> code(function->code());
5215 ScopeInfo<> sinfo(*code);
5216
5217 // Traverse the saved contexts chain to find the active context for the
5218 // selected frame.
5219 SaveContext* save = Top::save_context();
5220 while (save != NULL && reinterpret_cast<Address>(save) < frame->sp()) {
5221 save = save->prev();
5222 }
5223 ASSERT(save != NULL);
5224 SaveContext savex;
5225 Top::set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226
5227 // Create the (empty) function replacing the function on the stack frame for
5228 // the purpose of evaluating in the context created below. It is important
5229 // that this function does not describe any parameters and local variables
5230 // in the context. If it does then this will cause problems with the lookup
5231 // in Context::Lookup, where context slots for parameters and local variables
5232 // are looked at before the extension object.
5233 Handle<JSFunction> go_between =
5234 Factory::NewFunction(Factory::empty_string(), Factory::undefined_value());
5235 go_between->set_context(function->context());
5236#ifdef DEBUG
5237 ScopeInfo<> go_between_sinfo(go_between->shared()->code());
5238 ASSERT(go_between_sinfo.number_of_parameters() == 0);
5239 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
5240#endif
5241
5242 // Allocate and initialize a context extension object with all the
5243 // arguments, stack locals heap locals and extension properties of the
5244 // debugged function.
5245 Handle<JSObject> context_ext = Factory::NewJSObject(Top::object_function());
5246 // First fill all parameters to the context extension.
5247 for (int i = 0; i < sinfo.number_of_parameters(); ++i) {
5248 SetProperty(context_ext,
5249 sinfo.parameter_name(i),
5250 Handle<Object>(frame->GetParameter(i)), NONE);
5251 }
5252 // Second fill all stack locals to the context extension.
5253 for (int i = 0; i < sinfo.number_of_stack_slots(); i++) {
5254 SetProperty(context_ext,
5255 sinfo.stack_slot_name(i),
5256 Handle<Object>(frame->GetExpression(i)), NONE);
5257 }
5258 // Third fill all context locals to the context extension.
5259 Handle<Context> frame_context(Context::cast(frame->context()));
5260 Handle<Context> function_context(frame_context->fcontext());
5261 for (int i = Context::MIN_CONTEXT_SLOTS;
5262 i < sinfo.number_of_context_slots();
5263 ++i) {
5264 int context_index =
5265 ScopeInfo<>::ContextSlotIndex(*code, *sinfo.context_slot_name(i), NULL);
5266 SetProperty(context_ext,
5267 sinfo.context_slot_name(i),
5268 Handle<Object>(function_context->get(context_index)), NONE);
5269 }
5270 // Finally copy any properties from the function context extension. This will
5271 // be variables introduced by eval.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00005272 if (function_context->has_extension() &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005273 !function_context->IsGlobalContext()) {
5274 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
5275 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext);
5276 for (int i = 0; i < keys->length(); i++) {
5277 // Names of variables introduced by eval are strings.
5278 ASSERT(keys->get(i)->IsString());
5279 Handle<String> key(String::cast(keys->get(i)));
5280 SetProperty(context_ext, key, GetProperty(ext, key), NONE);
5281 }
5282 }
5283
5284 // Allocate a new context for the debug evaluation and set the extension
5285 // object build.
5286 Handle<Context> context =
5287 Factory::NewFunctionContext(Context::MIN_CONTEXT_SLOTS, go_between);
5288 context->set_extension(*context_ext);
5289 // Copy any with contexts present and chain them in front of this context.
5290 context = CopyWithContextChain(frame_context, context);
5291
5292 // Wrap the evaluation statement in a new function compiled in the newly
5293 // created context. The function has one parameter which has to be called
5294 // 'arguments'. This it to have access to what would have been 'arguments' in
5295 // the function beeing debugged.
5296 // function(arguments,__source__) {return eval(__source__);}
5297 static const char* source_str =
5298 "function(arguments,__source__){return eval(__source__);}";
5299 static const int source_str_length = strlen(source_str);
5300 Handle<String> function_source =
5301 Factory::NewStringFromAscii(Vector<const char>(source_str,
5302 source_str_length));
5303 Handle<JSFunction> boilerplate =
ager@chromium.org236ad962008-09-25 09:45:57 +00005304 Compiler::CompileEval(function_source, 0, context->IsGlobalContext());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005305 if (boilerplate.is_null()) return Failure::Exception();
5306 Handle<JSFunction> compiled_function =
5307 Factory::NewFunctionFromBoilerplate(boilerplate, context);
5308
5309 // Invoke the result of the compilation to get the evaluation function.
5310 bool has_pending_exception;
5311 Handle<Object> receiver(frame->receiver());
5312 Handle<Object> evaluation_function =
5313 Execution::Call(compiled_function, receiver, 0, NULL,
5314 &has_pending_exception);
5315
5316 Handle<Object> arguments = GetArgumentsObject(frame, function, code, &sinfo,
5317 function_context);
5318
5319 // Invoke the evaluation function and return the result.
5320 const int argc = 2;
5321 Object** argv[argc] = { arguments.location(),
5322 Handle<Object>::cast(source).location() };
5323 Handle<Object> result =
5324 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
5325 argc, argv, &has_pending_exception);
5326 return *result;
5327}
5328
5329
5330static Object* Runtime_DebugEvaluateGlobal(Arguments args) {
5331 HandleScope scope;
5332
5333 // Check the execution state and decode arguments frame and source to be
5334 // evaluated.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005335 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005336 Object* check_result = Runtime_CheckExecutionState(args);
5337 if (check_result->IsFailure()) return check_result;
5338 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +00005339 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
5340
5341 // Handle the processing of break.
5342 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005343
5344 // Enter the top context from before the debugger was invoked.
5345 SaveContext save;
5346 SaveContext* top = &save;
5347 while (top != NULL && *top->context() == *Debug::debug_context()) {
5348 top = top->prev();
5349 }
5350 if (top != NULL) {
5351 Top::set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005352 }
5353
5354 // Get the global context now set to the top context from before the
5355 // debugger was invoked.
5356 Handle<Context> context = Top::global_context();
5357
5358 // Compile the source to be evaluated.
ager@chromium.org236ad962008-09-25 09:45:57 +00005359 Handle<JSFunction> boilerplate(Compiler::CompileEval(source, 0, true));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005360 if (boilerplate.is_null()) return Failure::Exception();
5361 Handle<JSFunction> compiled_function =
5362 Handle<JSFunction>(Factory::NewFunctionFromBoilerplate(boilerplate,
5363 context));
5364
5365 // Invoke the result of the compilation to get the evaluation function.
5366 bool has_pending_exception;
5367 Handle<Object> receiver = Top::global();
5368 Handle<Object> result =
5369 Execution::Call(compiled_function, receiver, 0, NULL,
5370 &has_pending_exception);
5371 return *result;
5372}
5373
5374
5375// Helper function used by Runtime_DebugGetLoadedScripts below.
5376static int DebugGetLoadedScripts(FixedArray* instances, int instances_size) {
5377 NoHandleAllocation ha;
5378 AssertNoAllocation no_alloc;
5379
5380 // Get hold of the current empty script.
5381 Context* context = Top::context()->global_context();
5382 Script* empty = context->empty_script();
5383
5384 // Scan heap for Script objects.
5385 int count = 0;
5386 HeapIterator iterator;
5387 while (iterator.has_next()) {
5388 HeapObject* obj = iterator.next();
5389 ASSERT(obj != NULL);
5390 if (obj->IsScript() && obj != empty) {
5391 if (instances != NULL && count < instances_size) {
5392 instances->set(count, obj);
5393 }
5394 count++;
5395 }
5396 }
5397
5398 return count;
5399}
5400
5401
5402static Object* Runtime_DebugGetLoadedScripts(Arguments args) {
5403 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +00005404 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005405
5406 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
5407 // rid of all the cached script wrappes and the second gets rid of the
5408 // scripts which is no longer referenced.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005409 Heap::CollectAllGarbage();
5410 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411
5412 // Get the number of scripts.
5413 int count;
5414 count = DebugGetLoadedScripts(NULL, 0);
5415
5416 // Allocate an array to hold the result.
5417 Handle<FixedArray> instances = Factory::NewFixedArray(count);
5418
5419 // Fill the script objects.
5420 count = DebugGetLoadedScripts(*instances, count);
5421
5422 // Convert the script objects to proper JS objects.
5423 for (int i = 0; i < count; i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005424 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
5425 // Get the script wrapper in a local handle before calling GetScriptWrapper,
5426 // because using
5427 // instances->set(i, *GetScriptWrapper(script))
5428 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
5429 // already have deferenced the instances handle.
5430 Handle<JSValue> wrapper = GetScriptWrapper(script);
5431 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005432 }
5433
5434 // Return result as a JS array.
5435 Handle<JSObject> result = Factory::NewJSObject(Top::array_function());
5436 Handle<JSArray>::cast(result)->SetContent(*instances);
5437 return *result;
5438}
5439
5440
5441// Helper function used by Runtime_DebugReferencedBy below.
5442static int DebugReferencedBy(JSObject* target,
5443 Object* instance_filter, int max_references,
5444 FixedArray* instances, int instances_size,
5445 JSFunction* context_extension_function,
5446 JSFunction* arguments_function) {
5447 NoHandleAllocation ha;
5448 AssertNoAllocation no_alloc;
5449
5450 // Iterate the heap.
5451 int count = 0;
5452 JSObject* last = NULL;
5453 HeapIterator iterator;
5454 while (iterator.has_next() &&
5455 (max_references == 0 || count < max_references)) {
5456 // Only look at all JSObjects.
5457 HeapObject* heap_obj = iterator.next();
5458 if (heap_obj->IsJSObject()) {
5459 // Skip context extension objects and argument arrays as these are
5460 // checked in the context of functions using them.
5461 JSObject* obj = JSObject::cast(heap_obj);
5462 if (obj->map()->constructor() == context_extension_function ||
5463 obj->map()->constructor() == arguments_function) {
5464 continue;
5465 }
5466
5467 // Check if the JS object has a reference to the object looked for.
5468 if (obj->ReferencesObject(target)) {
5469 // Check instance filter if supplied. This is normally used to avoid
5470 // references from mirror objects (see Runtime_IsInPrototypeChain).
5471 if (!instance_filter->IsUndefined()) {
5472 Object* V = obj;
5473 while (true) {
5474 Object* prototype = V->GetPrototype();
5475 if (prototype->IsNull()) {
5476 break;
5477 }
5478 if (instance_filter == prototype) {
5479 obj = NULL; // Don't add this object.
5480 break;
5481 }
5482 V = prototype;
5483 }
5484 }
5485
5486 if (obj != NULL) {
5487 // Valid reference found add to instance array if supplied an update
5488 // count.
5489 if (instances != NULL && count < instances_size) {
5490 instances->set(count, obj);
5491 }
5492 last = obj;
5493 count++;
5494 }
5495 }
5496 }
5497 }
5498
5499 // Check for circular reference only. This can happen when the object is only
5500 // referenced from mirrors and has a circular reference in which case the
5501 // object is not really alive and would have been garbage collected if not
5502 // referenced from the mirror.
5503 if (count == 1 && last == target) {
5504 count = 0;
5505 }
5506
5507 // Return the number of referencing objects found.
5508 return count;
5509}
5510
5511
5512// Scan the heap for objects with direct references to an object
5513// args[0]: the object to find references to
5514// args[1]: constructor function for instances to exclude (Mirror)
5515// args[2]: the the maximum number of objects to return
5516static Object* Runtime_DebugReferencedBy(Arguments args) {
5517 ASSERT(args.length() == 3);
5518
5519 // First perform a full GC in order to avoid references from dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005520 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005521
5522 // Check parameters.
5523 CONVERT_CHECKED(JSObject, target, args[0]);
5524 Object* instance_filter = args[1];
5525 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
5526 instance_filter->IsJSObject());
5527 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
5528 RUNTIME_ASSERT(max_references >= 0);
5529
5530 // Get the constructor function for context extension and arguments array.
5531 JSFunction* context_extension_function =
5532 Top::context()->global_context()->context_extension_function();
5533 JSObject* arguments_boilerplate =
5534 Top::context()->global_context()->arguments_boilerplate();
5535 JSFunction* arguments_function =
5536 JSFunction::cast(arguments_boilerplate->map()->constructor());
5537
5538 // Get the number of referencing objects.
5539 int count;
5540 count = DebugReferencedBy(target, instance_filter, max_references,
5541 NULL, 0,
5542 context_extension_function, arguments_function);
5543
5544 // Allocate an array to hold the result.
5545 Object* object = Heap::AllocateFixedArray(count);
5546 if (object->IsFailure()) return object;
5547 FixedArray* instances = FixedArray::cast(object);
5548
5549 // Fill the referencing objects.
5550 count = DebugReferencedBy(target, instance_filter, max_references,
5551 instances, count,
5552 context_extension_function, arguments_function);
5553
5554 // Return result as JS array.
5555 Object* result =
5556 Heap::AllocateJSObject(
5557 Top::context()->global_context()->array_function());
5558 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5559 return result;
5560}
5561
5562
5563// Helper function used by Runtime_DebugConstructedBy below.
5564static int DebugConstructedBy(JSFunction* constructor, int max_references,
5565 FixedArray* instances, int instances_size) {
5566 AssertNoAllocation no_alloc;
5567
5568 // Iterate the heap.
5569 int count = 0;
5570 HeapIterator iterator;
5571 while (iterator.has_next() &&
5572 (max_references == 0 || count < max_references)) {
5573 // Only look at all JSObjects.
5574 HeapObject* heap_obj = iterator.next();
5575 if (heap_obj->IsJSObject()) {
5576 JSObject* obj = JSObject::cast(heap_obj);
5577 if (obj->map()->constructor() == constructor) {
5578 // Valid reference found add to instance array if supplied an update
5579 // count.
5580 if (instances != NULL && count < instances_size) {
5581 instances->set(count, obj);
5582 }
5583 count++;
5584 }
5585 }
5586 }
5587
5588 // Return the number of referencing objects found.
5589 return count;
5590}
5591
5592
5593// Scan the heap for objects constructed by a specific function.
5594// args[0]: the constructor to find instances of
5595// args[1]: the the maximum number of objects to return
5596static Object* Runtime_DebugConstructedBy(Arguments args) {
5597 ASSERT(args.length() == 2);
5598
5599 // First perform a full GC in order to avoid dead objects.
ager@chromium.org9258b6b2008-09-11 09:11:10 +00005600 Heap::CollectAllGarbage();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601
5602 // Check parameters.
5603 CONVERT_CHECKED(JSFunction, constructor, args[0]);
5604 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
5605 RUNTIME_ASSERT(max_references >= 0);
5606
5607 // Get the number of referencing objects.
5608 int count;
5609 count = DebugConstructedBy(constructor, max_references, NULL, 0);
5610
5611 // Allocate an array to hold the result.
5612 Object* object = Heap::AllocateFixedArray(count);
5613 if (object->IsFailure()) return object;
5614 FixedArray* instances = FixedArray::cast(object);
5615
5616 // Fill the referencing objects.
5617 count = DebugConstructedBy(constructor, max_references, instances, count);
5618
5619 // Return result as JS array.
5620 Object* result =
5621 Heap::AllocateJSObject(
5622 Top::context()->global_context()->array_function());
5623 if (!result->IsFailure()) JSArray::cast(result)->SetContent(instances);
5624 return result;
5625}
5626
5627
5628static Object* Runtime_GetPrototype(Arguments args) {
5629 ASSERT(args.length() == 1);
5630
5631 CONVERT_CHECKED(JSObject, obj, args[0]);
5632
5633 return obj->GetPrototype();
5634}
5635
5636
5637static Object* Runtime_SystemBreak(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005638 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005639 CPU::DebugBreak();
5640 return Heap::undefined_value();
5641}
5642
5643
5644// Finds the script object from the script data. NOTE: This operation uses
5645// heap traversal to find the function generated for the source position
5646// for the requested break point. For lazily compiled functions several heap
5647// traversals might be required rendering this operation as a rather slow
5648// operation. However for setting break points which is normally done through
5649// some kind of user interaction the performance is not crucial.
5650static Handle<Object> Runtime_GetScriptFromScriptName(
5651 Handle<String> script_name) {
5652 // Scan the heap for Script objects to find the script with the requested
5653 // script data.
5654 Handle<Script> script;
5655 HeapIterator iterator;
5656 while (script.is_null() && iterator.has_next()) {
5657 HeapObject* obj = iterator.next();
5658 // If a script is found check if it has the script data requested.
5659 if (obj->IsScript()) {
5660 if (Script::cast(obj)->name()->IsString()) {
5661 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
5662 script = Handle<Script>(Script::cast(obj));
5663 }
5664 }
5665 }
5666 }
5667
5668 // If no script with the requested script data is found return undefined.
5669 if (script.is_null()) return Factory::undefined_value();
5670
5671 // Return the script found.
5672 return GetScriptWrapper(script);
5673}
5674
5675
5676// Get the script object from script data. NOTE: Regarding performance
5677// see the NOTE for GetScriptFromScriptData.
5678// args[0]: script data for the script to find the source for
5679static Object* Runtime_GetScript(Arguments args) {
5680 HandleScope scope;
5681
5682 ASSERT(args.length() == 1);
5683
5684 CONVERT_CHECKED(String, script_name, args[0]);
5685
5686 // Find the requested script.
5687 Handle<Object> result =
5688 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
5689 return *result;
5690}
5691
5692
5693static Object* Runtime_FunctionGetAssemblerCode(Arguments args) {
5694#ifdef DEBUG
5695 HandleScope scope;
5696 ASSERT(args.length() == 1);
5697 // Get the function and make sure it is compiled.
5698 CONVERT_ARG_CHECKED(JSFunction, func, 0);
5699 if (!func->is_compiled() && !CompileLazy(func, KEEP_EXCEPTION)) {
5700 return Failure::Exception();
5701 }
5702 func->code()->PrintLn();
5703#endif // DEBUG
5704 return Heap::undefined_value();
5705}
5706
5707
5708static Object* Runtime_Abort(Arguments args) {
5709 ASSERT(args.length() == 2);
5710 OS::PrintError("abort: %s\n", reinterpret_cast<char*>(args[0]) +
5711 Smi::cast(args[1])->value());
5712 Top::PrintStack();
5713 OS::Abort();
5714 UNREACHABLE();
5715 return NULL;
5716}
5717
5718
kasper.lund44510672008-07-25 07:37:58 +00005719#ifdef DEBUG
5720// ListNatives is ONLY used by the fuzz-natives.js in debug mode
5721// Exclude the code in release mode.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005722static Object* Runtime_ListNatives(Arguments args) {
mads.s.ager31e71382008-08-13 09:32:07 +00005723 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005724 HandleScope scope;
5725 Handle<JSArray> result = Factory::NewJSArray(0);
5726 int index = 0;
5727#define ADD_ENTRY(Name, argc) \
5728 { \
5729 HandleScope inner; \
5730 Handle<String> name = \
5731 Factory::NewStringFromAscii(Vector<const char>(#Name, strlen(#Name))); \
5732 Handle<JSArray> pair = Factory::NewJSArray(0); \
5733 SetElement(pair, 0, name); \
5734 SetElement(pair, 1, Handle<Smi>(Smi::FromInt(argc))); \
5735 SetElement(result, index++, pair); \
5736 }
5737 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
5738#undef ADD_ENTRY
5739 return *result;
5740}
kasper.lund44510672008-07-25 07:37:58 +00005741#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005742
5743
5744static Object* Runtime_IS_VAR(Arguments args) {
5745 UNREACHABLE(); // implemented as macro in the parser
5746 return NULL;
5747}
5748
5749
5750// ----------------------------------------------------------------------------
5751// Implementation of Runtime
5752
5753#define F(name, nargs) \
5754 { #name, "RuntimeStub_" #name, FUNCTION_ADDR(Runtime_##name), nargs, \
5755 static_cast<int>(Runtime::k##name) },
5756
5757static Runtime::Function Runtime_functions[] = {
5758 RUNTIME_FUNCTION_LIST(F)
5759 { NULL, NULL, NULL, 0, -1 }
5760};
5761
5762#undef F
5763
5764
5765Runtime::Function* Runtime::FunctionForId(FunctionId fid) {
5766 ASSERT(0 <= fid && fid < kNofFunctions);
5767 return &Runtime_functions[fid];
5768}
5769
5770
5771Runtime::Function* Runtime::FunctionForName(const char* name) {
5772 for (Function* f = Runtime_functions; f->name != NULL; f++) {
5773 if (strcmp(f->name, name) == 0) {
5774 return f;
5775 }
5776 }
5777 return NULL;
5778}
5779
5780
5781void Runtime::PerformGC(Object* result) {
5782 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00005783 if (failure->IsRetryAfterGC()) {
5784 // Try to do a garbage collection; ignore it if it fails. The C
5785 // entry stub will throw an out-of-memory exception in that case.
5786 Heap::CollectGarbage(failure->requested(), failure->allocation_space());
5787 } else {
5788 // Handle last resort GC and make sure to allow future allocations
5789 // to grow the heap without causing GCs (if possible).
5790 Counters::gc_last_resort_from_js.Increment();
5791 Heap::CollectAllGarbage();
5792 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005793}
5794
5795
5796} } // namespace v8::internal