blob: e0f507e1774bbd7c7d500994f40a07e74ae8f1e6 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 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"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
110 JSObject* boilerplate) {
111 StackLimitCheck check(isolate);
112 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000117 if (!maybe_result->ToObject(&result)) return maybe_result;
118 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000119 JSObject* copy = JSObject::cast(result);
120
121 // Deep copy local properties.
122 if (copy->HasFastProperties()) {
123 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000124 for (int i = 0; i < properties->length(); i++) {
125 Object* value = properties->get(i);
126 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000127 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000128 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000129 if (!maybe_result->ToObject(&result)) return maybe_result;
130 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000131 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000132 }
133 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000134 int nof = copy->map()->inobject_properties();
135 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000136 Object* value = copy->InObjectPropertyAt(i);
137 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000138 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000140 if (!maybe_result->ToObject(&result)) return maybe_result;
141 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000142 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000143 }
144 }
145 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000147 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000148 if (!maybe_result->ToObject(&result)) return maybe_result;
149 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000150 FixedArray* names = FixedArray::cast(result);
151 copy->GetLocalPropertyNames(names, 0);
152 for (int i = 0; i < names->length(); i++) {
153 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000156 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 // Only deep copy fields from the object literal expression.
158 // In particular, don't try to copy the length attribute of
159 // an array.
160 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 Object* value =
162 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000163 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000164 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000165 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000166 if (!maybe_result->ToObject(&result)) return maybe_result;
167 }
168 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000169 // Creating object copy for literals. No strict mode needed.
170 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000171 if (!maybe_result->ToObject(&result)) return maybe_result;
172 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000173 }
174 }
175 }
176
177 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000179 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000180 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000181 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000182 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000183 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000184 if (elements->map() == heap->fixed_cow_array_map()) {
185 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000186#ifdef DEBUG
187 for (int i = 0; i < elements->length(); i++) {
188 ASSERT(!elements->get(i)->IsJSObject());
189 }
190#endif
191 } else {
192 for (int i = 0; i < elements->length(); i++) {
193 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000194 ASSERT(value->IsSmi() ||
195 value->IsTheHole() ||
196 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 if (value->IsJSObject()) {
198 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000199 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
200 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000201 if (!maybe_result->ToObject(&result)) return maybe_result;
202 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000203 elements->set(i, result);
204 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000205 }
206 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000207 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000208 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000209 case DICTIONARY_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000210 NumberDictionary* element_dictionary = copy->element_dictionary();
211 int capacity = element_dictionary->Capacity();
212 for (int i = 0; i < capacity; i++) {
213 Object* k = element_dictionary->KeyAt(i);
214 if (element_dictionary->IsKey(k)) {
215 Object* value = element_dictionary->ValueAt(i);
216 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000217 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000218 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
219 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000220 if (!maybe_result->ToObject(&result)) return maybe_result;
221 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000222 element_dictionary->ValueAtPut(i, result);
223 }
224 }
225 }
226 break;
227 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000228 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000229 UNIMPLEMENTED();
230 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000231 case EXTERNAL_PIXEL_ELEMENTS:
232 case EXTERNAL_BYTE_ELEMENTS:
233 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
234 case EXTERNAL_SHORT_ELEMENTS:
235 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
236 case EXTERNAL_INT_ELEMENTS:
237 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
238 case EXTERNAL_FLOAT_ELEMENTS:
239 case EXTERNAL_DOUBLE_ELEMENTS:
240 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000241 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000242 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 }
244 return copy;
245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000251}
252
253
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000254RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000255 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000256 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000257}
258
259
ager@chromium.org236ad962008-09-25 09:45:57 +0000260static Handle<Map> ComputeObjectLiteralMap(
261 Handle<Context> context,
262 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000263 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000265 int properties_length = constant_properties->length();
266 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000267 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000268 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000270 for (int p = 0; p != properties_length; p += 2) {
271 Object* key = constant_properties->get(p);
272 uint32_t element_index = 0;
273 if (key->IsSymbol()) {
274 number_of_symbol_keys++;
275 } else if (key->ToArrayIndex(&element_index)) {
276 // An index key does not require space in the property backing store.
277 number_of_properties--;
278 } else {
279 // Bail out as a non-symbol non-index key makes caching impossible.
280 // ASSERT to make sure that the if condition after the loop is false.
281 ASSERT(number_of_symbol_keys != number_of_properties);
282 break;
283 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000285 // If we only have symbols and array indices among keys then we can
286 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000287 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000288 if ((number_of_symbol_keys == number_of_properties) &&
289 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000290 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 Handle<FixedArray> keys =
292 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000293 if (number_of_symbol_keys > 0) {
294 int index = 0;
295 for (int p = 0; p < properties_length; p += 2) {
296 Object* key = constant_properties->get(p);
297 if (key->IsSymbol()) {
298 keys->set(index++, key);
299 }
300 }
301 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000302 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000303 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000304 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305 }
306 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000307 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000309 Handle<Map>(context->object_function()->initial_map()),
310 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311}
312
313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000314static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
317 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000318
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000319
320static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000321 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000322 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000323 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 bool should_have_fast_elements,
325 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000326 // Get the global context from the literals array. This is the
327 // context in which the function was created and we use the object
328 // function from this context to create the object literal. We do
329 // not use the object function from the current global context
330 // because this might be the object function from another context
331 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000332 Handle<Context> context =
333 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000335 // In case we have function literals, we want the object to be in
336 // slow properties mode for now. We don't go in the map cache because
337 // maps with constant functions can't be shared if the functions are
338 // not the same (which is the common case).
339 bool is_result_from_cache = false;
340 Handle<Map> map = has_function_literal
341 ? Handle<Map>(context->object_function()->initial_map())
342 : ComputeObjectLiteralMap(context,
343 constant_properties,
344 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000345
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000346 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000347
348 // Normalize the elements of the boilerplate to save space if needed.
349 if (!should_have_fast_elements) NormalizeElements(boilerplate);
350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000351 // Add the constant properties to the boilerplate.
352 int length = constant_properties->length();
353 bool should_transform =
354 !is_result_from_cache && boilerplate->HasFastProperties();
355 if (should_transform || has_function_literal) {
356 // Normalize the properties of object to avoid n^2 behavior
357 // when extending the object multiple properties. Indicate the number of
358 // properties to be added.
359 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
360 }
361
362 for (int index = 0; index < length; index +=2) {
363 Handle<Object> key(constant_properties->get(index+0), isolate);
364 Handle<Object> value(constant_properties->get(index+1), isolate);
365 if (value->IsFixedArray()) {
366 // The value contains the constant_properties of a
367 // simple object or array literal.
368 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
369 value = CreateLiteralBoilerplate(isolate, literals, array);
370 if (value.is_null()) return value;
371 }
372 Handle<Object> result;
373 uint32_t element_index = 0;
374 if (key->IsSymbol()) {
375 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
376 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000377 result = SetOwnElement(boilerplate,
378 element_index,
379 value,
380 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000381 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000382 Handle<String> name(String::cast(*key));
383 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000384 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
385 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 } else if (key->ToArrayIndex(&element_index)) {
388 // Array index (uint32).
389 result = SetOwnElement(boilerplate,
390 element_index,
391 value,
392 kNonStrictMode);
393 } else {
394 // Non-uint32 number.
395 ASSERT(key->IsNumber());
396 double num = key->Number();
397 char arr[100];
398 Vector<char> buffer(arr, ARRAY_SIZE(arr));
399 const char* str = DoubleToCString(num, buffer);
400 Handle<String> name =
401 isolate->factory()->NewStringFromAscii(CStrVector(str));
402 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
403 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000404 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 // If setting the property on the boilerplate throws an
406 // exception, the exception is converted to an empty handle in
407 // the handle based operations. In that case, we need to
408 // convert back to an exception.
409 if (result.is_null()) return result;
410 }
411
412 // Transform to fast properties if necessary. For object literals with
413 // containing function literals we defer this operation until after all
414 // computed properties have been assigned so that we can generate
415 // constant function properties.
416 if (should_transform && !has_function_literal) {
417 TransformToFastProperties(boilerplate,
418 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000419 }
420
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000422}
423
424
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000425static const int kSmiOnlyLiteralMinimumLength = 1024;
426
427
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000428static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000430 Handle<FixedArray> literals,
431 Handle<FixedArray> elements) {
432 // Create the JSArray.
433 Handle<JSFunction> constructor(
434 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000436
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000437 if (elements->length() > kSmiOnlyLiteralMinimumLength) {
438 Handle<Map> smi_array_map = isolate->factory()->GetElementsTransitionMap(
439 Handle<JSObject>::cast(object),
440 FAST_SMI_ONLY_ELEMENTS);
441 HeapObject::cast(*object)->set_map(*smi_array_map);
442 }
443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 const bool is_cow =
445 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000448
449 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000450 bool has_non_smi = false;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000451 if (is_cow) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000452 // Copy-on-write arrays must be shallow (and simple).
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000453 for (int i = 0; i < content->length(); i++) {
454 Object* current = content->get(i);
455 ASSERT(!current->IsFixedArray());
456 if (!current->IsSmi() && !current->IsTheHole()) {
457 has_non_smi = true;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000458 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000459 }
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000460#if DEBUG
461 for (int i = 0; i < content->length(); i++) {
462 ASSERT(!content->get(i)->IsFixedArray());
463 }
464#endif
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000465 } else {
466 for (int i = 0; i < content->length(); i++) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000467 Object* current = content->get(i);
468 if (current->IsFixedArray()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000469 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000470 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000471 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
472 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000473 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000474 if (result.is_null()) return result;
475 content->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000476 has_non_smi = true;
477 } else {
478 if (!current->IsSmi() && !current->IsTheHole()) {
479 has_non_smi = true;
480 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000481 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 }
483 }
484
485 // Set the elements.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000486 Handle<JSArray> js_object(Handle<JSArray>::cast(object));
487 isolate->factory()->SetContent(js_object, content);
488
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000489 if (has_non_smi && js_object->HasFastSmiOnlyElements()) {
490 isolate->factory()->EnsureCanContainNonSmiElements(js_object);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000491 }
492
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000493 return object;
494}
495
496
497static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000498 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000499 Handle<FixedArray> literals,
500 Handle<FixedArray> array) {
501 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000502 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000503 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000504 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000505 return CreateObjectLiteralBoilerplate(isolate,
506 literals,
507 elements,
508 true,
509 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000510 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000511 return CreateObjectLiteralBoilerplate(isolate,
512 literals,
513 elements,
514 false,
515 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000516 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000518 default:
519 UNREACHABLE();
520 return Handle<Object>::null();
521 }
522}
523
524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000525RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000526 // Takes a FixedArray of elements containing the literal elements of
527 // the array literal and produces JSArray with those elements.
528 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000529 // which contains the context from which to get the Array function
530 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000531 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000532 ASSERT(args.length() == 3);
533 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000534 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000535 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000536
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 Handle<Object> object =
538 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000539 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000541 // Update the functions literal and return the boilerplate.
542 literals->set(literals_index, *object);
543 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544}
545
546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000547RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000549 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000551 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000552 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000553 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
555 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556
557 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000558 Handle<Object> boilerplate(literals->get(literals_index), isolate);
559 if (*boilerplate == isolate->heap()->undefined_value()) {
560 boilerplate = CreateObjectLiteralBoilerplate(isolate,
561 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000562 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 should_have_fast_elements,
564 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 if (boilerplate.is_null()) return Failure::Exception();
566 // Update the functions literal and return the boilerplate.
567 literals->set(literals_index, *boilerplate);
568 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000570}
571
572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000573RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000575 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000577 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000578 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000579 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000580 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
581 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000582
583 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000584 Handle<Object> boilerplate(literals->get(literals_index), isolate);
585 if (*boilerplate == isolate->heap()->undefined_value()) {
586 boilerplate = CreateObjectLiteralBoilerplate(isolate,
587 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000588 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 should_have_fast_elements,
590 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000591 if (boilerplate.is_null()) return Failure::Exception();
592 // Update the functions literal and return the boilerplate.
593 literals->set(literals_index, *boilerplate);
594 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000596}
597
598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000599RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000601 ASSERT(args.length() == 3);
602 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000603 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000604 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
605
606 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000607 Handle<Object> boilerplate(literals->get(literals_index), isolate);
608 if (*boilerplate == isolate->heap()->undefined_value()) {
609 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000610 if (boilerplate.is_null()) return Failure::Exception();
611 // Update the functions literal and return the boilerplate.
612 literals->set(literals_index, *boilerplate);
613 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000614 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000620 ASSERT(args.length() == 3);
621 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000622 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000623 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
624
625 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<Object> boilerplate(literals->get(literals_index), isolate);
627 if (*boilerplate == isolate->heap()->undefined_value()) {
628 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000629 if (boilerplate.is_null()) return Failure::Exception();
630 // Update the functions literal and return the boilerplate.
631 literals->set(literals_index, *boilerplate);
632 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000633 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000635 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000636 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000637 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000638}
639
640
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000641RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
642 ASSERT(args.length() == 2);
643 Object* handler = args[0];
644 Object* prototype = args[1];
645 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000646 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000647 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
648}
649
650
lrn@chromium.org34e60782011-09-15 07:25:40 +0000651RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
652 ASSERT(args.length() == 4);
653 Object* handler = args[0];
654 Object* call_trap = args[1];
655 Object* construct_trap = args[2];
656 Object* prototype = args[3];
657 Object* used_prototype =
658 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
659 return isolate->heap()->AllocateJSFunctionProxy(
660 handler, call_trap, construct_trap, used_prototype);
661}
662
663
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000664RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
665 ASSERT(args.length() == 1);
666 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000667 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000668}
669
670
lrn@chromium.org34e60782011-09-15 07:25:40 +0000671RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
672 ASSERT(args.length() == 1);
673 Object* obj = args[0];
674 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
675}
676
677
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000678RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
679 ASSERT(args.length() == 1);
680 CONVERT_CHECKED(JSProxy, proxy, args[0]);
681 return proxy->handler();
682}
683
684
lrn@chromium.org34e60782011-09-15 07:25:40 +0000685RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
686 ASSERT(args.length() == 1);
687 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
688 return proxy->call_trap();
689}
690
691
692RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
693 ASSERT(args.length() == 1);
694 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
695 return proxy->construct_trap();
696}
697
698
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000699RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
700 ASSERT(args.length() == 1);
701 CONVERT_CHECKED(JSProxy, proxy, args[0]);
702 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000703 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000704}
705
706
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000707RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
708 HandleScope scope(isolate);
709 ASSERT(args.length() == 1);
710 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
711 ASSERT(weakmap->map()->inobject_properties() == 0);
712 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
713 weakmap->set_table(*table);
714 weakmap->set_next(Smi::FromInt(0));
715 return *weakmap;
716}
717
718
719RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
720 NoHandleAllocation ha;
721 ASSERT(args.length() == 2);
722 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000723 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
724 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000725}
726
727
728RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
729 HandleScope scope(isolate);
730 ASSERT(args.length() == 3);
731 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000732 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000733 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000734 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000735 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
736 weakmap->set_table(*new_table);
737 return *value;
738}
739
740
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000741RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000742 NoHandleAllocation ha;
743 ASSERT(args.length() == 1);
744 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000745 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000746 return JSObject::cast(obj)->class_name();
747}
748
ager@chromium.org7c537e22008-10-16 08:43:32 +0000749
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000750RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
751 NoHandleAllocation ha;
752 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000753 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
754 Object* obj = input_obj;
755 // We don't expect access checks to be needed on JSProxy objects.
756 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000757 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000758 if (obj->IsAccessCheckNeeded() &&
759 !isolate->MayNamedAccess(JSObject::cast(obj),
760 isolate->heap()->Proto_symbol(),
761 v8::ACCESS_GET)) {
762 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
763 return isolate->heap()->undefined_value();
764 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000765 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000766 } while (obj->IsJSObject() &&
767 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000768 return obj;
769}
770
771
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000772RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773 NoHandleAllocation ha;
774 ASSERT(args.length() == 2);
775 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
776 Object* O = args[0];
777 Object* V = args[1];
778 while (true) {
779 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000780 if (prototype->IsNull()) return isolate->heap()->false_value();
781 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000782 V = prototype;
783 }
784}
785
786
ager@chromium.org9085a012009-05-11 19:22:57 +0000787// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000788RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000789 NoHandleAllocation ha;
790 ASSERT(args.length() == 2);
791 CONVERT_CHECKED(JSObject, jsobject, args[0]);
792 CONVERT_CHECKED(JSObject, proto, args[1]);
793
794 // Sanity checks. The old prototype (that we are replacing) could
795 // theoretically be null, but if it is not null then check that we
796 // didn't already install a hidden prototype here.
797 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
798 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
799 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
800
801 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000802 Object* map_or_failure;
803 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
804 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
805 return maybe_map_or_failure;
806 }
807 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000808 Map* new_proto_map = Map::cast(map_or_failure);
809
lrn@chromium.org303ada72010-10-27 09:33:13 +0000810 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
811 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
812 return maybe_map_or_failure;
813 }
814 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000815 Map* new_map = Map::cast(map_or_failure);
816
817 // Set proto's prototype to be the old prototype of the object.
818 new_proto_map->set_prototype(jsobject->GetPrototype());
819 proto->set_map(new_proto_map);
820 new_proto_map->set_is_hidden_prototype();
821
822 // Set the object's prototype to proto.
823 new_map->set_prototype(proto);
824 jsobject->set_map(new_map);
825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000826 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000827}
828
829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000830RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000832 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000833 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000834 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000835}
836
837
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000838// Recursively traverses hidden prototypes if property is not found
839static void GetOwnPropertyImplementation(JSObject* obj,
840 String* name,
841 LookupResult* result) {
842 obj->LocalLookupRealNamedProperty(name, result);
843
844 if (!result->IsProperty()) {
845 Object* proto = obj->GetPrototype();
846 if (proto->IsJSObject() &&
847 JSObject::cast(proto)->map()->is_hidden_prototype())
848 GetOwnPropertyImplementation(JSObject::cast(proto),
849 name, result);
850 }
851}
852
853
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000854static bool CheckAccessException(LookupResult* result,
855 v8::AccessType access_type) {
856 if (result->type() == CALLBACKS) {
857 Object* callback = result->GetCallbackObject();
858 if (callback->IsAccessorInfo()) {
859 AccessorInfo* info = AccessorInfo::cast(callback);
860 bool can_access =
861 (access_type == v8::ACCESS_HAS &&
862 (info->all_can_read() || info->all_can_write())) ||
863 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
864 (access_type == v8::ACCESS_SET && info->all_can_write());
865 return can_access;
866 }
867 }
868
869 return false;
870}
871
872
873static bool CheckAccess(JSObject* obj,
874 String* name,
875 LookupResult* result,
876 v8::AccessType access_type) {
877 ASSERT(result->IsProperty());
878
879 JSObject* holder = result->holder();
880 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000881 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000882 while (true) {
883 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000884 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000885 // Access check callback denied the access, but some properties
886 // can have a special permissions which override callbacks descision
887 // (currently see v8::AccessControl).
888 break;
889 }
890
891 if (current == holder) {
892 return true;
893 }
894
895 current = JSObject::cast(current->GetPrototype());
896 }
897
898 // API callbacks can have per callback access exceptions.
899 switch (result->type()) {
900 case CALLBACKS: {
901 if (CheckAccessException(result, access_type)) {
902 return true;
903 }
904 break;
905 }
906 case INTERCEPTOR: {
907 // If the object has an interceptor, try real named properties.
908 // Overwrite the result to fetch the correct property later.
909 holder->LookupRealNamedProperty(name, result);
910 if (result->IsProperty()) {
911 if (CheckAccessException(result, access_type)) {
912 return true;
913 }
914 }
915 break;
916 }
917 default:
918 break;
919 }
920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000922 return false;
923}
924
925
926// TODO(1095): we should traverse hidden prototype hierachy as well.
927static bool CheckElementAccess(JSObject* obj,
928 uint32_t index,
929 v8::AccessType access_type) {
930 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 return false;
933 }
934
935 return true;
936}
937
938
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000939// Enumerator used as indices into the array returned from GetOwnProperty
940enum PropertyDescriptorIndices {
941 IS_ACCESSOR_INDEX,
942 VALUE_INDEX,
943 GETTER_INDEX,
944 SETTER_INDEX,
945 WRITABLE_INDEX,
946 ENUMERABLE_INDEX,
947 CONFIGURABLE_INDEX,
948 DESCRIPTOR_SIZE
949};
950
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000951// Returns an array with the property description:
952// if args[1] is not a property on args[0]
953// returns undefined
954// if args[1] is a data property on args[0]
955// [false, value, Writeable, Enumerable, Configurable]
956// if args[1] is an accessor on args[0]
957// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000958RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000959 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 Heap* heap = isolate->heap();
961 HandleScope scope(isolate);
962 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
963 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000964 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000965 CONVERT_ARG_CHECKED(JSObject, obj, 0);
966 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000967
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000968 // This could be an element.
969 uint32_t index;
970 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000971 switch (obj->HasLocalElement(index)) {
972 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000973 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000974
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000975 case JSObject::STRING_CHARACTER_ELEMENT: {
976 // Special handling of string objects according to ECMAScript 5
977 // 15.5.5.2. Note that this might be a string object with elements
978 // other than the actual string value. This is covered by the
979 // subsequent cases.
980 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
981 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000982 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000983
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000985 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000986 elms->set(WRITABLE_INDEX, heap->false_value());
987 elms->set(ENUMERABLE_INDEX, heap->false_value());
988 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000989 return *desc;
990 }
991
992 case JSObject::INTERCEPTED_ELEMENT:
993 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000995 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000996 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000997 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000998 elms->set(WRITABLE_INDEX, heap->true_value());
999 elms->set(ENUMERABLE_INDEX, heap->true_value());
1000 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001001 return *desc;
1002 }
1003
1004 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001005 Handle<JSObject> holder = obj;
1006 if (obj->IsJSGlobalProxy()) {
1007 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001009 ASSERT(proto->IsJSGlobalObject());
1010 holder = Handle<JSObject>(JSObject::cast(proto));
1011 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001012 FixedArray* elements = FixedArray::cast(holder->elements());
1013 NumberDictionary* dictionary = NULL;
1014 if (elements->map() == heap->non_strict_arguments_elements_map()) {
1015 dictionary = NumberDictionary::cast(elements->get(1));
1016 } else {
1017 dictionary = NumberDictionary::cast(elements);
1018 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001019 int entry = dictionary->FindEntry(index);
1020 ASSERT(entry != NumberDictionary::kNotFound);
1021 PropertyDetails details = dictionary->DetailsAt(entry);
1022 switch (details.type()) {
1023 case CALLBACKS: {
1024 // This is an accessor property with getter and/or setter.
1025 FixedArray* callbacks =
1026 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001027 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001028 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
1029 elms->set(GETTER_INDEX, callbacks->get(0));
1030 }
1031 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
1032 elms->set(SETTER_INDEX, callbacks->get(1));
1033 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001034 break;
1035 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001036 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001037 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001038 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001039 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001040 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001041 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001043 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001044 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001045 default:
1046 UNREACHABLE();
1047 break;
1048 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001049 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1050 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001051 return *desc;
1052 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001053 }
1054 }
1055
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001056 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001058
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001059 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001061 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001062
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001063 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001064 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001065 }
1066
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1068 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001069
1070 bool is_js_accessor = (result.type() == CALLBACKS) &&
1071 (result.GetCallbackObject()->IsFixedArray());
1072
1073 if (is_js_accessor) {
1074 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001076
1077 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1078 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1079 elms->set(GETTER_INDEX, structure->get(0));
1080 }
1081 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1082 elms->set(SETTER_INDEX, structure->get(1));
1083 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001084 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1086 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001087
1088 PropertyAttributes attrs;
1089 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001090 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001091 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1092 if (!maybe_value->ToObject(&value)) return maybe_value;
1093 }
1094 elms->set(VALUE_INDEX, value);
1095 }
1096
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001097 return *desc;
1098}
1099
1100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001101RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001102 ASSERT(args.length() == 1);
1103 CONVERT_CHECKED(JSObject, obj, args[0]);
1104 return obj->PreventExtensions();
1105}
1106
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001108RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001109 ASSERT(args.length() == 1);
1110 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001111 if (obj->IsJSGlobalProxy()) {
1112 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001113 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001114 ASSERT(proto->IsJSGlobalObject());
1115 obj = JSObject::cast(proto);
1116 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001117 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001118}
1119
1120
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001121RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001124 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1125 CONVERT_ARG_CHECKED(String, pattern, 1);
1126 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001127 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1128 if (result.is_null()) return Failure::Exception();
1129 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001130}
1131
1132
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001133RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001134 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001136 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001137 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001138}
1139
1140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001141RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 ASSERT(args.length() == 1);
1143 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001144 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001145 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001146}
1147
1148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001149RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150 ASSERT(args.length() == 2);
1151 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001152 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001153 int index = field->value();
1154 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1155 InstanceType type = templ->map()->instance_type();
1156 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1157 type == OBJECT_TEMPLATE_INFO_TYPE);
1158 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001159 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001160 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1161 } else {
1162 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1163 }
1164 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001165}
1166
1167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001168RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001169 ASSERT(args.length() == 1);
1170 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001171 Map* old_map = object->map();
1172 bool needs_access_checks = old_map->is_access_check_needed();
1173 if (needs_access_checks) {
1174 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001175 Object* new_map;
1176 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1177 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1178 }
ager@chromium.org32912102009-01-16 10:38:43 +00001179
1180 Map::cast(new_map)->set_is_access_check_needed(false);
1181 object->set_map(Map::cast(new_map));
1182 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001183 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001184}
1185
1186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001187RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001188 ASSERT(args.length() == 1);
1189 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001190 Map* old_map = object->map();
1191 if (!old_map->is_access_check_needed()) {
1192 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001193 Object* new_map;
1194 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1195 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1196 }
ager@chromium.org32912102009-01-16 10:38:43 +00001197
1198 Map::cast(new_map)->set_is_access_check_needed(true);
1199 object->set_map(Map::cast(new_map));
1200 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001201 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001202}
1203
1204
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001205static Failure* ThrowRedeclarationError(Isolate* isolate,
1206 const char* type,
1207 Handle<String> name) {
1208 HandleScope scope(isolate);
1209 Handle<Object> type_handle =
1210 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001211 Handle<Object> args[2] = { type_handle, name };
1212 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001213 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1214 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215}
1216
1217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001218RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001219 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001220 HandleScope scope(isolate);
1221 Handle<GlobalObject> global = Handle<GlobalObject>(
1222 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223
ager@chromium.org3811b432009-10-28 14:53:37 +00001224 Handle<Context> context = args.at<Context>(0);
1225 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001226 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001228 // Traverse the name/value pairs and set the properties.
1229 int length = pairs->length();
1230 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001233 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234
1235 // We have to declare a global const property. To capture we only
1236 // assign to it when evaluating the assignment for "const x =
1237 // <expr>" the initial value is the hole.
1238 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001239 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240 if (value->IsUndefined() || is_const_property) {
1241 // Lookup the property in the global object, and don't set the
1242 // value of the variable if the property is already there.
1243 LookupResult lookup;
1244 global->Lookup(*name, &lookup);
1245 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001246 // We found an existing property. Unless it was an interceptor
1247 // that claims the property is absent, skip this declaration.
1248 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249 continue;
1250 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001251 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1252 if (attributes != ABSENT) {
1253 continue;
1254 }
1255 // Fall-through and introduce the absent property by using
1256 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 }
1258 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001259 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001260 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001261 Handle<SharedFunctionInfo> shared =
1262 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001263 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001264 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1265 context,
1266 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001267 value = function;
1268 }
1269
1270 LookupResult lookup;
1271 global->LocalLookup(*name, &lookup);
1272
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 // Compute the property attributes. According to ECMA-262, section
1274 // 13, page 71, the property must be read-only and
1275 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1276 // property as read-only, so we don't either.
1277 int attr = NONE;
1278 if ((flags & kDeclareGlobalsEvalFlag) == 0) {
1279 attr |= DONT_DELETE;
1280 }
1281 bool is_native = (flags & kDeclareGlobalsNativeFlag) != 0;
1282 if (is_const_property || (is_native && is_function_declaration)) {
1283 attr |= READ_ONLY;
1284 }
1285
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001286 // Safari does not allow the invocation of callback setters for
1287 // function declarations. To mimic this behavior, we do not allow
1288 // the invocation of setters for function values. This makes a
1289 // difference for global functions with the same names as event
1290 // handlers such as "function onload() {}". Firefox does call the
1291 // onload setter in those case and Safari does not. We follow
1292 // Safari for compatibility.
1293 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001294 // Do not change DONT_DELETE to false from true.
1295 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001296 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001297 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001298 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1299
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001300 RETURN_IF_EMPTY_HANDLE(isolate,
1301 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001302 name,
1303 value,
1304 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001306 StrictModeFlag strict_mode =
1307 ((flags & kDeclareGlobalsStrictModeFlag) != 0) ? kStrictMode
1308 : kNonStrictMode;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 RETURN_IF_EMPTY_HANDLE(isolate,
1310 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001311 name,
1312 value,
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 static_cast<PropertyAttributes>(attr),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001314 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 }
1316 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001317
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 ASSERT(!isolate->has_pending_exception());
1319 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001320}
1321
1322
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001323RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001324 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001325 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001326
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001327 // Declarations are always made in a function or global context. In the
1328 // case of eval code, the context passed is the context of the caller,
1329 // which may be some nested context and not the declaration context.
1330 RUNTIME_ASSERT(args[0]->IsContext());
1331 Handle<Context> context(Context::cast(args[0])->declaration_context());
1332
ager@chromium.org7c537e22008-10-16 08:43:32 +00001333 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001334 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001335 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001336 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001337
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 int index;
1339 PropertyAttributes attributes;
1340 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001341 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001342 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001343 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344
1345 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001346 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1348 // Functions are not read-only.
1349 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1350 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001351 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352 }
1353
1354 // Initialize it if necessary.
1355 if (*initial_value != NULL) {
1356 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001357 ASSERT(holder.is_identical_to(context));
1358 if (((attributes & READ_ONLY) == 0) ||
1359 context->get(index)->IsTheHole()) {
1360 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361 }
1362 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001363 // Slow case: The property is in the context extension object of a
1364 // function context or the global object of a global context.
1365 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001366 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001367 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001368 SetProperty(object, name, initial_value, mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369 }
1370 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001373 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001374 // "declared" in the function context's extension context or as a
1375 // property of the the global object.
1376 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001377 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001378 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001379 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001380 // Context extension objects are allocated lazily.
1381 ASSERT(context->IsFunctionContext());
1382 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001385 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001386 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387
ager@chromium.org7c537e22008-10-16 08:43:32 +00001388 // Declare the property by setting it to the initial value if provided,
1389 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1390 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001391 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001392 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001393 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001394 // Declaring a const context slot is a conflicting declaration if
1395 // there is a callback with that name in a prototype. It is
1396 // allowed to introduce const variables in
1397 // JSContextExtensionObjects. They are treated specially in
1398 // SetProperty and no setters are invoked for those since they are
1399 // not real JSObjects.
1400 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001401 !object->IsJSContextExtensionObject()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001402 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001403 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001404 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001406 }
1407 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001408 RETURN_IF_EMPTY_HANDLE(isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001409 SetProperty(object, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001410 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001411 }
1412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001413 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001414}
1415
1416
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001417RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001419 // args[0] == name
1420 // args[1] == strict_mode
1421 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001422
1423 // Determine if we need to assign to the variable if it already
1424 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001425 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1426 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427
1428 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001429 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001430 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001431 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001432 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
1434 // According to ECMA-262, section 12.2, page 62, the property must
1435 // not be deletable.
1436 PropertyAttributes attributes = DONT_DELETE;
1437
1438 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001439 // there, there is a property with this name in the prototype chain.
1440 // We follow Safari and Firefox behavior and only set the property
1441 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001442 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001443 // Note that objects can have hidden prototypes, so we need to traverse
1444 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001445 Object* object = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447 while (object->IsJSObject() &&
1448 JSObject::cast(object)->map()->is_hidden_prototype()) {
1449 JSObject* raw_holder = JSObject::cast(object);
1450 raw_holder->LocalLookup(*name, &lookup);
1451 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1452 HandleScope handle_scope(isolate);
1453 Handle<JSObject> holder(raw_holder);
1454 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1455 // Update the raw pointer in case it's changed due to GC.
1456 raw_holder = *holder;
1457 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1458 // Found an interceptor that's not read only.
1459 if (assign) {
1460 return raw_holder->SetProperty(
1461 &lookup, *name, args[2], attributes, strict_mode);
1462 } else {
1463 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001464 }
1465 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001466 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001467 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468 }
1469
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001470 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001472 if (assign) {
1473 return global->SetProperty(*name, args[2], attributes, strict_mode);
1474 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476}
1477
1478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001479RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 // All constants are declared with an initial value. The name
1481 // of the constant is the first argument and the initial value
1482 // is the second.
1483 RUNTIME_ASSERT(args.length() == 2);
1484 CONVERT_ARG_CHECKED(String, name, 0);
1485 Handle<Object> value = args.at<Object>(1);
1486
1487 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001488 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489
1490 // According to ECMA-262, section 12.2, page 62, the property must
1491 // not be deletable. Since it's a const, it must be READ_ONLY too.
1492 PropertyAttributes attributes =
1493 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1494
1495 // Lookup the property locally in the global object. If it isn't
1496 // there, we add the property and take special precautions to always
1497 // add it as a local property even in case of callbacks in the
1498 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001499 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001500 LookupResult lookup;
1501 global->LocalLookup(*name, &lookup);
1502 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001503 return global->SetLocalPropertyIgnoreAttributes(*name,
1504 *value,
1505 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001506 }
1507
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001508 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001509 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001511 HandleScope handle_scope(isolate);
1512 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001513
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001514 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 // property through an interceptor and only do it if it's
1516 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001517 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001518 RETURN_IF_EMPTY_HANDLE(isolate,
1519 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001520 name,
1521 value,
1522 attributes,
1523 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 return *value;
1525 }
1526
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001527 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 // constant. For now, we determine this by checking if the
1529 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001530 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001531 PropertyType type = lookup.type();
1532 if (type == FIELD) {
1533 FixedArray* properties = global->properties();
1534 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001535 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 properties->set(index, *value);
1537 }
1538 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001539 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1540 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001541 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 }
1543 } else {
1544 // Ignore re-initialization of constants that have already been
1545 // assigned a function value.
1546 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1547 }
1548
1549 // Use the set value as the result of the operation.
1550 return *value;
1551}
1552
1553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001554RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001555 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 ASSERT(args.length() == 3);
1557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001559 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001561 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001562 RUNTIME_ASSERT(args[1]->IsContext());
1563 Handle<Context> context(Context::cast(args[1])->declaration_context());
1564
1565 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001566
1567 int index;
1568 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001569 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001570 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001571 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001572 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001575 ASSERT(holder->IsContext());
1576 // Property was found in a context. Perform the assignment if we
1577 // found some non-constant or an uninitialized constant.
1578 Handle<Context> context = Handle<Context>::cast(holder);
1579 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1580 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 }
1582 return *value;
1583 }
1584
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001585 // The property could not be found, we introduce it as a property of the
1586 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001587 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001588 Handle<JSObject> global = Handle<JSObject>(
1589 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001590 // Strict mode not needed (const disallowed in strict mode).
1591 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001592 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001593 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001594 return *value;
1595 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001596
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001597 // The property was present in some function's context extension object,
1598 // as a property on the subject of a with, or as a property of the global
1599 // object.
1600 //
1601 // In most situations, eval-introduced consts should still be present in
1602 // the context extension object. However, because declaration and
1603 // initialization are separate, the property might have been deleted
1604 // before we reach the initialization point.
1605 //
1606 // Example:
1607 //
1608 // function f() { eval("delete x; const x;"); }
1609 //
1610 // In that case, the initialization behaves like a normal assignment.
1611 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001612
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001613 if (*object == context->extension()) {
1614 // This is the property that was introduced by the const declaration.
1615 // Set it if it hasn't been set before. NOTE: We cannot use
1616 // GetProperty() to get the current value as it 'unholes' the value.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001617 LookupResult lookup;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001618 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 ASSERT(lookup.IsProperty()); // the property was declared
1620 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1621
1622 PropertyType type = lookup.type();
1623 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001624 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001625 int index = lookup.GetFieldIndex();
1626 if (properties->get(index)->IsTheHole()) {
1627 properties->set(index, *value);
1628 }
1629 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001630 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1631 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001632 }
1633 } else {
1634 // We should not reach here. Any real, named property should be
1635 // either a field or a dictionary slot.
1636 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001637 }
1638 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001639 // The property was found on some other object. Set it if it is not a
1640 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001641 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001642 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001643 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001644 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001645 SetProperty(object, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001646 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001648
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001649 return *value;
1650}
1651
1652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001653RUNTIME_FUNCTION(MaybeObject*,
1654 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001655 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001656 ASSERT(args.length() == 2);
1657 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001658 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001659 if (object->HasFastProperties()) {
1660 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1661 }
1662 return *object;
1663}
1664
1665
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001666RUNTIME_FUNCTION(MaybeObject*, Runtime_NonSmiElementStored) {
1667 ASSERT(args.length() == 1);
1668 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001669 if (object->HasFastSmiOnlyElements()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001670 MaybeObject* maybe_map = object->GetElementsTransitionMap(FAST_ELEMENTS);
1671 Map* map;
1672 if (!maybe_map->To<Map>(&map)) return maybe_map;
1673 object->set_map(Map::cast(map));
1674 }
1675 return *object;
1676}
1677
1678
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001679RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001680 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001681 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001682 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1683 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001684 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001685 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001686 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001687 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001688 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001689 RUNTIME_ASSERT(index >= 0);
1690 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001692 Handle<Object> result = RegExpImpl::Exec(regexp,
1693 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001694 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001695 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001696 if (result.is_null()) return Failure::Exception();
1697 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001698}
1699
1700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001701RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001702 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001703 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001704 if (elements_count < 0 ||
1705 elements_count > FixedArray::kMaxLength ||
1706 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001707 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001708 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001709 Object* new_object;
1710 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001712 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1713 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001714 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001715 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1716 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001717 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1718 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001719 {
1720 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001721 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001722 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001724 }
1725 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001726 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001727 array->set_elements(elements);
1728 array->set_length(Smi::FromInt(elements_count));
1729 // Write in-object properties after the length of the array.
1730 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1731 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1732 return array;
1733}
1734
1735
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001736RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001737 AssertNoAllocation no_alloc;
1738 ASSERT(args.length() == 5);
1739 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1740 CONVERT_CHECKED(String, source, args[1]);
1741
1742 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001744
1745 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001747
1748 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001750
1751 Map* map = regexp->map();
1752 Object* constructor = map->constructor();
1753 if (constructor->IsJSFunction() &&
1754 JSFunction::cast(constructor)->initial_map() == map) {
1755 // If we still have the original map, set in-object properties directly.
1756 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1757 // TODO(lrn): Consider skipping write barrier on booleans as well.
1758 // Both true and false should be in oldspace at all times.
1759 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1760 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1761 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1762 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1763 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001764 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001765 return regexp;
1766 }
1767
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001769 PropertyAttributes final =
1770 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1771 PropertyAttributes writable =
1772 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001774 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001775 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001776 source,
1777 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001778 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001780 global,
1781 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001782 ASSERT(!result->IsFailure());
1783 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001784 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001785 ignoreCase,
1786 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001787 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001789 multiline,
1790 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001791 ASSERT(!result->IsFailure());
1792 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001793 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001794 Smi::FromInt(0),
1795 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001796 ASSERT(!result->IsFailure());
1797 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001798 return regexp;
1799}
1800
1801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001802RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001803 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001804 ASSERT(args.length() == 1);
1805 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1806 // This is necessary to enable fast checks for absence of elements
1807 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001808 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001809 return Smi::FromInt(0);
1810}
1811
1812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1814 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001815 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001816 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001817 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1818 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1819 Handle<JSFunction> optimized =
1820 isolate->factory()->NewFunction(key,
1821 JS_OBJECT_TYPE,
1822 JSObject::kHeaderSize,
1823 code,
1824 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001825 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001826 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001827 return optimized;
1828}
1829
1830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001831RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001832 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001833 ASSERT(args.length() == 1);
1834 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1835
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001836 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1837 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1838 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1839 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1840 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1841 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1842 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001843
1844 return *holder;
1845}
1846
1847
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001848RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1849 NoHandleAllocation handle_free;
1850 ASSERT(args.length() == 1);
1851 CONVERT_CHECKED(JSFunction, function, args[0]);
1852 SharedFunctionInfo* shared = function->shared();
1853 if (shared->native() || shared->strict_mode()) {
1854 return isolate->heap()->undefined_value();
1855 }
1856 // Returns undefined for strict or native functions, or
1857 // the associated global receiver for "normal" functions.
1858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001859 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001860 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001861 return global_context->global()->global_receiver();
1862}
1863
1864
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001865RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001866 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001867 ASSERT(args.length() == 4);
1868 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001869 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870 Handle<String> pattern = args.at<String>(2);
1871 Handle<String> flags = args.at<String>(3);
1872
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001873 // Get the RegExp function from the context in the literals array.
1874 // This is the RegExp function from the context in which the
1875 // function was created. We do not use the RegExp function from the
1876 // current global context because this might be the RegExp function
1877 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001878 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001879 Handle<JSFunction>(
1880 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001881 // Compute the regular expression literal.
1882 bool has_pending_exception;
1883 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001884 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1885 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001886 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001887 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001888 return Failure::Exception();
1889 }
1890 literals->set(index, *regexp);
1891 return *regexp;
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 NoHandleAllocation ha;
1897 ASSERT(args.length() == 1);
1898
1899 CONVERT_CHECKED(JSFunction, f, args[0]);
1900 return f->shared()->name();
1901}
1902
1903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001904RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001905 NoHandleAllocation ha;
1906 ASSERT(args.length() == 2);
1907
1908 CONVERT_CHECKED(JSFunction, f, args[0]);
1909 CONVERT_CHECKED(String, name, args[1]);
1910 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001911 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001912}
1913
1914
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001915RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1916 NoHandleAllocation ha;
1917 ASSERT(args.length() == 1);
1918 CONVERT_CHECKED(JSFunction, f, args[0]);
1919 return isolate->heap()->ToBoolean(
1920 f->shared()->name_should_print_as_anonymous());
1921}
1922
1923
1924RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1925 NoHandleAllocation ha;
1926 ASSERT(args.length() == 1);
1927 CONVERT_CHECKED(JSFunction, f, args[0]);
1928 f->shared()->set_name_should_print_as_anonymous(true);
1929 return isolate->heap()->undefined_value();
1930}
1931
1932
whesse@chromium.org7b260152011-06-20 15:33:18 +00001933RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1934 HandleScope scope(isolate);
1935 ASSERT(args.length() == 1);
1936
1937 CONVERT_CHECKED(JSFunction, fun, args[0]);
1938 fun->shared()->set_bound(true);
1939 return isolate->heap()->undefined_value();
1940}
1941
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001942RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001943 NoHandleAllocation ha;
1944 ASSERT(args.length() == 1);
1945
1946 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001947 Object* obj = f->RemovePrototype();
1948 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001950 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001951}
1952
1953
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001954RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001955 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 ASSERT(args.length() == 1);
1957
1958 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001959 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1960 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001961
1962 return *GetScriptWrapper(Handle<Script>::cast(script));
1963}
1964
1965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001966RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001967 NoHandleAllocation ha;
1968 ASSERT(args.length() == 1);
1969
1970 CONVERT_CHECKED(JSFunction, f, args[0]);
1971 return f->shared()->GetSourceCode();
1972}
1973
1974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001975RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976 NoHandleAllocation ha;
1977 ASSERT(args.length() == 1);
1978
1979 CONVERT_CHECKED(JSFunction, fun, args[0]);
1980 int pos = fun->shared()->start_position();
1981 return Smi::FromInt(pos);
1982}
1983
1984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001985RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001986 ASSERT(args.length() == 2);
1987
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001988 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001989 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1990
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001991 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1992
1993 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001994 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001995}
1996
1997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 2);
2001
2002 CONVERT_CHECKED(JSFunction, fun, args[0]);
2003 CONVERT_CHECKED(String, name, args[1]);
2004 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002005 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002006}
2007
2008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002009RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010 NoHandleAllocation ha;
2011 ASSERT(args.length() == 2);
2012
2013 CONVERT_CHECKED(JSFunction, fun, args[0]);
2014 CONVERT_CHECKED(Smi, length, args[1]);
2015 fun->shared()->set_length(length->value());
2016 return length;
2017}
2018
2019
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002020// Creates a local, readonly, property called length with the correct
2021// length (when read by the user). This effectively overwrites the
2022// interceptor used to normally provide the length.
2023RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2024 NoHandleAllocation ha;
2025 ASSERT(args.length() == 2);
2026 CONVERT_CHECKED(JSFunction, fun, args[0]);
2027 CONVERT_CHECKED(Smi, length, args[1]);
2028 MaybeObject* maybe_name =
2029 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2030 String* name;
2031 if (!maybe_name->To(&name)) return maybe_name;
2032 PropertyAttributes attr =
2033 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2034 return fun->AddProperty(name, length, attr, kNonStrictMode);
2035}
2036
2037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002038RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002039 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 ASSERT(args.length() == 2);
2041
2042 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002043 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002044 Object* obj;
2045 { MaybeObject* maybe_obj =
2046 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2047 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2048 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049 return args[0]; // return TOS
2050}
2051
2052
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002053RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2054 NoHandleAllocation ha;
2055 RUNTIME_ASSERT(args.length() == 1);
2056 CONVERT_CHECKED(JSFunction, function, args[0]);
2057
2058 MaybeObject* maybe_name =
2059 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2060 String* name;
2061 if (!maybe_name->To(&name)) return maybe_name;
2062
2063 if (function->HasFastProperties()) {
2064 // Construct a new field descriptor with updated attributes.
2065 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2066 int index = instance_desc->Search(name);
2067 ASSERT(index != DescriptorArray::kNotFound);
2068 PropertyDetails details(instance_desc->GetDetails(index));
2069 CallbacksDescriptor new_desc(name,
2070 instance_desc->GetValue(index),
2071 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2072 details.index());
2073 // Construct a new field descriptors array containing the new descriptor.
2074 Object* descriptors_unchecked;
2075 { MaybeObject* maybe_descriptors_unchecked =
2076 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2077 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2078 return maybe_descriptors_unchecked;
2079 }
2080 }
2081 DescriptorArray* new_descriptors =
2082 DescriptorArray::cast(descriptors_unchecked);
2083 // Create a new map featuring the new field descriptors array.
2084 Object* map_unchecked;
2085 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2086 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2087 return maybe_map_unchecked;
2088 }
2089 }
2090 Map* new_map = Map::cast(map_unchecked);
2091 new_map->set_instance_descriptors(new_descriptors);
2092 function->set_map(new_map);
2093 } else { // Dictionary properties.
2094 // Directly manipulate the property details.
2095 int entry = function->property_dictionary()->FindEntry(name);
2096 ASSERT(entry != StringDictionary::kNotFound);
2097 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2098 PropertyDetails new_details(
2099 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2100 details.type(),
2101 details.index());
2102 function->property_dictionary()->DetailsAtPut(entry, new_details);
2103 }
2104 return function;
2105}
2106
2107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002108RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002109 NoHandleAllocation ha;
2110 ASSERT(args.length() == 1);
2111
2112 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002113 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002114}
2115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002116
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002117RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002118 NoHandleAllocation ha;
2119 ASSERT(args.length() == 1);
2120
2121 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002122 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002123}
2124
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002126RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002127 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002128 ASSERT(args.length() == 2);
2129
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002130 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002131 Handle<Object> code = args.at<Object>(1);
2132
2133 Handle<Context> context(target->context());
2134
2135 if (!code->IsNull()) {
2136 RUNTIME_ASSERT(code->IsJSFunction());
2137 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002138 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002139
2140 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002141 return Failure::Exception();
2142 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002143 // Since we don't store the source for this we should never
2144 // optimize this.
2145 shared->code()->set_optimizable(false);
2146
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002147 // Set the code, scope info, formal parameter count,
2148 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002149 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002150 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002151 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002152 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002153 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002154 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002155 // Set the source code of the target function to undefined.
2156 // SetCode is only used for built-in constructors like String,
2157 // Array, and Object, and some web code
2158 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002159 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002160 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002161 // Clear the optimization hints related to the compiled code as these are no
2162 // longer valid when the code is overwritten.
2163 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164 context = Handle<Context>(fun->context());
2165
2166 // Make sure we get a fresh copy of the literal vector to avoid
2167 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002168 int number_of_literals = fun->NumberOfLiterals();
2169 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002170 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002171 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002172 // Insert the object, regexp and array functions in the literals
2173 // array prefix. These are the functions that will be used when
2174 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002175 literals->set(JSFunction::kLiteralGlobalContextIndex,
2176 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002178 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002179 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002180
2181 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2182 isolate->logger()->LogExistingFunction(
2183 shared, Handle<Code>(shared->code()));
2184 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002185 }
2186
2187 target->set_context(*context);
2188 return *target;
2189}
2190
2191
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002192RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002193 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002194 ASSERT(args.length() == 2);
2195 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002196 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002197 RUNTIME_ASSERT(num >= 0);
2198 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002199 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002200}
2201
2202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002203MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2204 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002205 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002206 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002207 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002208 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002209 }
2210 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002211 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002212}
2213
2214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002215RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002216 NoHandleAllocation ha;
2217 ASSERT(args.length() == 2);
2218
2219 CONVERT_CHECKED(String, subject, args[0]);
2220 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002221 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002222
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002223 uint32_t i = 0;
2224 if (index->IsSmi()) {
2225 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002226 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002227 i = value;
2228 } else {
2229 ASSERT(index->IsHeapNumber());
2230 double value = HeapNumber::cast(index)->value();
2231 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002232 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002233
2234 // Flatten the string. If someone wants to get a char at an index
2235 // in a cons string, it is likely that more indices will be
2236 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002237 Object* flat;
2238 { MaybeObject* maybe_flat = subject->TryFlatten();
2239 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2240 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 subject = String::cast(flat);
2242
2243 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002244 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002245 }
2246
2247 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002248}
2249
2250
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002251RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002252 NoHandleAllocation ha;
2253 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002254 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002255}
2256
lrn@chromium.org25156de2010-04-06 13:10:27 +00002257
2258class FixedArrayBuilder {
2259 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002260 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2261 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002262 length_(0),
2263 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002264 // Require a non-zero initial size. Ensures that doubling the size to
2265 // extend the array will work.
2266 ASSERT(initial_capacity > 0);
2267 }
2268
2269 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2270 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002271 length_(0),
2272 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002273 // Require a non-zero initial size. Ensures that doubling the size to
2274 // extend the array will work.
2275 ASSERT(backing_store->length() > 0);
2276 }
2277
2278 bool HasCapacity(int elements) {
2279 int length = array_->length();
2280 int required_length = length_ + elements;
2281 return (length >= required_length);
2282 }
2283
2284 void EnsureCapacity(int elements) {
2285 int length = array_->length();
2286 int required_length = length_ + elements;
2287 if (length < required_length) {
2288 int new_length = length;
2289 do {
2290 new_length *= 2;
2291 } while (new_length < required_length);
2292 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002293 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002294 array_->CopyTo(0, *extended_array, 0, length_);
2295 array_ = extended_array;
2296 }
2297 }
2298
2299 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002300 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002301 ASSERT(length_ < capacity());
2302 array_->set(length_, value);
2303 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002304 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002305 }
2306
2307 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002308 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002309 ASSERT(length_ < capacity());
2310 array_->set(length_, value);
2311 length_++;
2312 }
2313
2314 Handle<FixedArray> array() {
2315 return array_;
2316 }
2317
2318 int length() {
2319 return length_;
2320 }
2321
2322 int capacity() {
2323 return array_->length();
2324 }
2325
2326 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002327 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 result_array->set_length(Smi::FromInt(length_));
2329 return result_array;
2330 }
2331
2332 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002333 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002334 target_array->set_length(Smi::FromInt(length_));
2335 return target_array;
2336 }
2337
2338 private:
2339 Handle<FixedArray> array_;
2340 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002341 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002342};
2343
2344
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002345// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002346const int kStringBuilderConcatHelperLengthBits = 11;
2347const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002348
2349template <typename schar>
2350static inline void StringBuilderConcatHelper(String*,
2351 schar*,
2352 FixedArray*,
2353 int);
2354
lrn@chromium.org25156de2010-04-06 13:10:27 +00002355typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2356 StringBuilderSubstringLength;
2357typedef BitField<int,
2358 kStringBuilderConcatHelperLengthBits,
2359 kStringBuilderConcatHelperPositionBits>
2360 StringBuilderSubstringPosition;
2361
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002362
2363class ReplacementStringBuilder {
2364 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002365 ReplacementStringBuilder(Heap* heap,
2366 Handle<String> subject,
2367 int estimated_part_count)
2368 : heap_(heap),
2369 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002370 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002371 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002372 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002373 // Require a non-zero initial size. Ensures that doubling the size to
2374 // extend the array will work.
2375 ASSERT(estimated_part_count > 0);
2376 }
2377
lrn@chromium.org25156de2010-04-06 13:10:27 +00002378 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2379 int from,
2380 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002381 ASSERT(from >= 0);
2382 int length = to - from;
2383 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384 if (StringBuilderSubstringLength::is_valid(length) &&
2385 StringBuilderSubstringPosition::is_valid(from)) {
2386 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2387 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002388 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002389 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002390 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002391 builder->Add(Smi::FromInt(-length));
2392 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002393 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002394 }
2395
2396
2397 void EnsureCapacity(int elements) {
2398 array_builder_.EnsureCapacity(elements);
2399 }
2400
2401
2402 void AddSubjectSlice(int from, int to) {
2403 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002404 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002405 }
2406
2407
2408 void AddString(Handle<String> string) {
2409 int length = string->length();
2410 ASSERT(length > 0);
2411 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002412 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002413 is_ascii_ = false;
2414 }
2415 IncrementCharacterCount(length);
2416 }
2417
2418
2419 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002420 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002421 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002422 }
2423
2424 Handle<String> joined_string;
2425 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002426 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002428 char* char_buffer = seq->GetChars();
2429 StringBuilderConcatHelper(*subject_,
2430 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002431 *array_builder_.array(),
2432 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002433 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002434 } else {
2435 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002436 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002437 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002438 uc16* char_buffer = seq->GetChars();
2439 StringBuilderConcatHelper(*subject_,
2440 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002441 *array_builder_.array(),
2442 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002443 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002444 }
2445 return joined_string;
2446 }
2447
2448
2449 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002450 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002451 V8::FatalProcessOutOfMemory("String.replace result too large.");
2452 }
2453 character_count_ += by;
2454 }
2455
lrn@chromium.org25156de2010-04-06 13:10:27 +00002456 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002457 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002458 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002459
lrn@chromium.org25156de2010-04-06 13:10:27 +00002460 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2462 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 }
2464
2465
ager@chromium.org04921a82011-06-27 13:21:41 +00002466 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2467 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002468 }
2469
2470
2471 void AddElement(Object* element) {
2472 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002473 ASSERT(array_builder_.capacity() > array_builder_.length());
2474 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 }
2476
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002477 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002478 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002479 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002480 int character_count_;
2481 bool is_ascii_;
2482};
2483
2484
2485class CompiledReplacement {
2486 public:
2487 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002488 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489
2490 void Compile(Handle<String> replacement,
2491 int capture_count,
2492 int subject_length);
2493
2494 void Apply(ReplacementStringBuilder* builder,
2495 int match_from,
2496 int match_to,
2497 Handle<JSArray> last_match_info);
2498
2499 // Number of distinct parts of the replacement pattern.
2500 int parts() {
2501 return parts_.length();
2502 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002503
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002504 bool simple_hint() {
2505 return simple_hint_;
2506 }
2507
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002508 private:
2509 enum PartType {
2510 SUBJECT_PREFIX = 1,
2511 SUBJECT_SUFFIX,
2512 SUBJECT_CAPTURE,
2513 REPLACEMENT_SUBSTRING,
2514 REPLACEMENT_STRING,
2515
2516 NUMBER_OF_PART_TYPES
2517 };
2518
2519 struct ReplacementPart {
2520 static inline ReplacementPart SubjectMatch() {
2521 return ReplacementPart(SUBJECT_CAPTURE, 0);
2522 }
2523 static inline ReplacementPart SubjectCapture(int capture_index) {
2524 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2525 }
2526 static inline ReplacementPart SubjectPrefix() {
2527 return ReplacementPart(SUBJECT_PREFIX, 0);
2528 }
2529 static inline ReplacementPart SubjectSuffix(int subject_length) {
2530 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2531 }
2532 static inline ReplacementPart ReplacementString() {
2533 return ReplacementPart(REPLACEMENT_STRING, 0);
2534 }
2535 static inline ReplacementPart ReplacementSubString(int from, int to) {
2536 ASSERT(from >= 0);
2537 ASSERT(to > from);
2538 return ReplacementPart(-from, to);
2539 }
2540
2541 // If tag <= 0 then it is the negation of a start index of a substring of
2542 // the replacement pattern, otherwise it's a value from PartType.
2543 ReplacementPart(int tag, int data)
2544 : tag(tag), data(data) {
2545 // Must be non-positive or a PartType value.
2546 ASSERT(tag < NUMBER_OF_PART_TYPES);
2547 }
2548 // Either a value of PartType or a non-positive number that is
2549 // the negation of an index into the replacement string.
2550 int tag;
2551 // The data value's interpretation depends on the value of tag:
2552 // tag == SUBJECT_PREFIX ||
2553 // tag == SUBJECT_SUFFIX: data is unused.
2554 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2555 // tag == REPLACEMENT_SUBSTRING ||
2556 // tag == REPLACEMENT_STRING: data is index into array of substrings
2557 // of the replacement string.
2558 // tag <= 0: Temporary representation of the substring of the replacement
2559 // string ranging over -tag .. data.
2560 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2561 // substring objects.
2562 int data;
2563 };
2564
2565 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002566 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002567 Vector<Char> characters,
2568 int capture_count,
2569 int subject_length) {
2570 int length = characters.length();
2571 int last = 0;
2572 for (int i = 0; i < length; i++) {
2573 Char c = characters[i];
2574 if (c == '$') {
2575 int next_index = i + 1;
2576 if (next_index == length) { // No next character!
2577 break;
2578 }
2579 Char c2 = characters[next_index];
2580 switch (c2) {
2581 case '$':
2582 if (i > last) {
2583 // There is a substring before. Include the first "$".
2584 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2585 last = next_index + 1; // Continue after the second "$".
2586 } else {
2587 // Let the next substring start with the second "$".
2588 last = next_index;
2589 }
2590 i = next_index;
2591 break;
2592 case '`':
2593 if (i > last) {
2594 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2595 }
2596 parts->Add(ReplacementPart::SubjectPrefix());
2597 i = next_index;
2598 last = i + 1;
2599 break;
2600 case '\'':
2601 if (i > last) {
2602 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2603 }
2604 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2605 i = next_index;
2606 last = i + 1;
2607 break;
2608 case '&':
2609 if (i > last) {
2610 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2611 }
2612 parts->Add(ReplacementPart::SubjectMatch());
2613 i = next_index;
2614 last = i + 1;
2615 break;
2616 case '0':
2617 case '1':
2618 case '2':
2619 case '3':
2620 case '4':
2621 case '5':
2622 case '6':
2623 case '7':
2624 case '8':
2625 case '9': {
2626 int capture_ref = c2 - '0';
2627 if (capture_ref > capture_count) {
2628 i = next_index;
2629 continue;
2630 }
2631 int second_digit_index = next_index + 1;
2632 if (second_digit_index < length) {
2633 // Peek ahead to see if we have two digits.
2634 Char c3 = characters[second_digit_index];
2635 if ('0' <= c3 && c3 <= '9') { // Double digits.
2636 int double_digit_ref = capture_ref * 10 + c3 - '0';
2637 if (double_digit_ref <= capture_count) {
2638 next_index = second_digit_index;
2639 capture_ref = double_digit_ref;
2640 }
2641 }
2642 }
2643 if (capture_ref > 0) {
2644 if (i > last) {
2645 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2646 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002647 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002648 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2649 last = next_index + 1;
2650 }
2651 i = next_index;
2652 break;
2653 }
2654 default:
2655 i = next_index;
2656 break;
2657 }
2658 }
2659 }
2660 if (length > last) {
2661 if (last == 0) {
2662 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002663 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002664 } else {
2665 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2666 }
2667 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002668 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669 }
2670
2671 ZoneList<ReplacementPart> parts_;
2672 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002673 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002674};
2675
2676
2677void CompiledReplacement::Compile(Handle<String> replacement,
2678 int capture_count,
2679 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002680 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002681 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002682 String::FlatContent content = replacement->GetFlatContent();
2683 ASSERT(content.IsFlat());
2684 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002685 simple_hint_ = ParseReplacementPattern(&parts_,
2686 content.ToAsciiVector(),
2687 capture_count,
2688 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002689 } else {
2690 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002691 simple_hint_ = ParseReplacementPattern(&parts_,
2692 content.ToUC16Vector(),
2693 capture_count,
2694 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002695 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002696 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002697 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002698 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002699 int substring_index = 0;
2700 for (int i = 0, n = parts_.length(); i < n; i++) {
2701 int tag = parts_[i].tag;
2702 if (tag <= 0) { // A replacement string slice.
2703 int from = -tag;
2704 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002705 replacement_substrings_.Add(
2706 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002707 parts_[i].tag = REPLACEMENT_SUBSTRING;
2708 parts_[i].data = substring_index;
2709 substring_index++;
2710 } else if (tag == REPLACEMENT_STRING) {
2711 replacement_substrings_.Add(replacement);
2712 parts_[i].data = substring_index;
2713 substring_index++;
2714 }
2715 }
2716}
2717
2718
2719void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2720 int match_from,
2721 int match_to,
2722 Handle<JSArray> last_match_info) {
2723 for (int i = 0, n = parts_.length(); i < n; i++) {
2724 ReplacementPart part = parts_[i];
2725 switch (part.tag) {
2726 case SUBJECT_PREFIX:
2727 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2728 break;
2729 case SUBJECT_SUFFIX: {
2730 int subject_length = part.data;
2731 if (match_to < subject_length) {
2732 builder->AddSubjectSlice(match_to, subject_length);
2733 }
2734 break;
2735 }
2736 case SUBJECT_CAPTURE: {
2737 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002738 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002739 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2740 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2741 if (from >= 0 && to > from) {
2742 builder->AddSubjectSlice(from, to);
2743 }
2744 break;
2745 }
2746 case REPLACEMENT_SUBSTRING:
2747 case REPLACEMENT_STRING:
2748 builder->AddString(replacement_substrings_[part.data]);
2749 break;
2750 default:
2751 UNREACHABLE();
2752 }
2753 }
2754}
2755
2756
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002757void FindAsciiStringIndices(Vector<const char> subject,
2758 char pattern,
2759 ZoneList<int>* indices,
2760 unsigned int limit) {
2761 ASSERT(limit > 0);
2762 // Collect indices of pattern in subject using memchr.
2763 // Stop after finding at most limit values.
2764 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2765 const char* subject_end = subject_start + subject.length();
2766 const char* pos = subject_start;
2767 while (limit > 0) {
2768 pos = reinterpret_cast<const char*>(
2769 memchr(pos, pattern, subject_end - pos));
2770 if (pos == NULL) return;
2771 indices->Add(static_cast<int>(pos - subject_start));
2772 pos++;
2773 limit--;
2774 }
2775}
2776
2777
2778template <typename SubjectChar, typename PatternChar>
2779void FindStringIndices(Isolate* isolate,
2780 Vector<const SubjectChar> subject,
2781 Vector<const PatternChar> pattern,
2782 ZoneList<int>* indices,
2783 unsigned int limit) {
2784 ASSERT(limit > 0);
2785 // Collect indices of pattern in subject.
2786 // Stop after finding at most limit values.
2787 int pattern_length = pattern.length();
2788 int index = 0;
2789 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2790 while (limit > 0) {
2791 index = search.Search(subject, index);
2792 if (index < 0) return;
2793 indices->Add(index);
2794 index += pattern_length;
2795 limit--;
2796 }
2797}
2798
2799
2800void FindStringIndicesDispatch(Isolate* isolate,
2801 String* subject,
2802 String* pattern,
2803 ZoneList<int>* indices,
2804 unsigned int limit) {
2805 {
2806 AssertNoAllocation no_gc;
2807 String::FlatContent subject_content = subject->GetFlatContent();
2808 String::FlatContent pattern_content = pattern->GetFlatContent();
2809 ASSERT(subject_content.IsFlat());
2810 ASSERT(pattern_content.IsFlat());
2811 if (subject_content.IsAscii()) {
2812 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2813 if (pattern_content.IsAscii()) {
2814 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2815 if (pattern_vector.length() == 1) {
2816 FindAsciiStringIndices(subject_vector,
2817 pattern_vector[0],
2818 indices,
2819 limit);
2820 } else {
2821 FindStringIndices(isolate,
2822 subject_vector,
2823 pattern_vector,
2824 indices,
2825 limit);
2826 }
2827 } else {
2828 FindStringIndices(isolate,
2829 subject_vector,
2830 pattern_content.ToUC16Vector(),
2831 indices,
2832 limit);
2833 }
2834 } else {
2835 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002836 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002837 FindStringIndices(isolate,
2838 subject_vector,
2839 pattern_content.ToAsciiVector(),
2840 indices,
2841 limit);
2842 } else {
2843 FindStringIndices(isolate,
2844 subject_vector,
2845 pattern_content.ToUC16Vector(),
2846 indices,
2847 limit);
2848 }
2849 }
2850 }
2851}
2852
2853
2854template<typename ResultSeqString>
2855MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2856 Isolate* isolate,
2857 Handle<String> subject,
2858 Handle<JSRegExp> pattern_regexp,
2859 Handle<String> replacement) {
2860 ASSERT(subject->IsFlat());
2861 ASSERT(replacement->IsFlat());
2862
2863 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2864 ZoneList<int> indices(8);
2865 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2866 String* pattern =
2867 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2868 int subject_len = subject->length();
2869 int pattern_len = pattern->length();
2870 int replacement_len = replacement->length();
2871
2872 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2873
2874 int matches = indices.length();
2875 if (matches == 0) return *subject;
2876
2877 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2878 int subject_pos = 0;
2879 int result_pos = 0;
2880
2881 Handle<ResultSeqString> result;
2882 if (ResultSeqString::kHasAsciiEncoding) {
2883 result = Handle<ResultSeqString>::cast(
2884 isolate->factory()->NewRawAsciiString(result_len));
2885 } else {
2886 result = Handle<ResultSeqString>::cast(
2887 isolate->factory()->NewRawTwoByteString(result_len));
2888 }
2889
2890 for (int i = 0; i < matches; i++) {
2891 // Copy non-matched subject content.
2892 if (subject_pos < indices.at(i)) {
2893 String::WriteToFlat(*subject,
2894 result->GetChars() + result_pos,
2895 subject_pos,
2896 indices.at(i));
2897 result_pos += indices.at(i) - subject_pos;
2898 }
2899
2900 // Replace match.
2901 if (replacement_len > 0) {
2902 String::WriteToFlat(*replacement,
2903 result->GetChars() + result_pos,
2904 0,
2905 replacement_len);
2906 result_pos += replacement_len;
2907 }
2908
2909 subject_pos = indices.at(i) + pattern_len;
2910 }
2911 // Add remaining subject content at the end.
2912 if (subject_pos < subject_len) {
2913 String::WriteToFlat(*subject,
2914 result->GetChars() + result_pos,
2915 subject_pos,
2916 subject_len);
2917 }
2918 return *result;
2919}
2920
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002921
lrn@chromium.org303ada72010-10-27 09:33:13 +00002922MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002923 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002924 String* subject,
2925 JSRegExp* regexp,
2926 String* replacement,
2927 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002928 ASSERT(subject->IsFlat());
2929 ASSERT(replacement->IsFlat());
2930
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002931 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002932
2933 int length = subject->length();
2934 Handle<String> subject_handle(subject);
2935 Handle<JSRegExp> regexp_handle(regexp);
2936 Handle<String> replacement_handle(replacement);
2937 Handle<JSArray> last_match_info_handle(last_match_info);
2938 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2939 subject_handle,
2940 0,
2941 last_match_info_handle);
2942 if (match.is_null()) {
2943 return Failure::Exception();
2944 }
2945 if (match->IsNull()) {
2946 return *subject_handle;
2947 }
2948
2949 int capture_count = regexp_handle->CaptureCount();
2950
2951 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002952 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002953 CompiledReplacement compiled_replacement;
2954 compiled_replacement.Compile(replacement_handle,
2955 capture_count,
2956 length);
2957
2958 bool is_global = regexp_handle->GetFlags().is_global();
2959
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002960 // Shortcut for simple non-regexp global replacements
2961 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002962 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002963 compiled_replacement.simple_hint()) {
2964 if (subject_handle->HasOnlyAsciiChars() &&
2965 replacement_handle->HasOnlyAsciiChars()) {
2966 return StringReplaceStringWithString<SeqAsciiString>(
2967 isolate, subject_handle, regexp_handle, replacement_handle);
2968 } else {
2969 return StringReplaceStringWithString<SeqTwoByteString>(
2970 isolate, subject_handle, regexp_handle, replacement_handle);
2971 }
2972 }
2973
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002974 // Guessing the number of parts that the final result string is built
2975 // from. Global regexps can match any number of times, so we guess
2976 // conservatively.
2977 int expected_parts =
2978 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002979 ReplacementStringBuilder builder(isolate->heap(),
2980 subject_handle,
2981 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002982
2983 // Index of end of last match.
2984 int prev = 0;
2985
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002986 // Number of parts added by compiled replacement plus preceeding
2987 // string and possibly suffix after last match. It is possible for
2988 // all components to use two elements when encoded as two smis.
2989 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002990 bool matched = true;
2991 do {
2992 ASSERT(last_match_info_handle->HasFastElements());
2993 // Increase the capacity of the builder before entering local handle-scope,
2994 // so its internal buffer can safely allocate a new handle if it grows.
2995 builder.EnsureCapacity(parts_added_per_loop);
2996
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002997 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002998 int start, end;
2999 {
3000 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003001 FixedArray* match_info_array =
3002 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003003
3004 ASSERT_EQ(capture_count * 2 + 2,
3005 RegExpImpl::GetLastCaptureCount(match_info_array));
3006 start = RegExpImpl::GetCapture(match_info_array, 0);
3007 end = RegExpImpl::GetCapture(match_info_array, 1);
3008 }
3009
3010 if (prev < start) {
3011 builder.AddSubjectSlice(prev, start);
3012 }
3013 compiled_replacement.Apply(&builder,
3014 start,
3015 end,
3016 last_match_info_handle);
3017 prev = end;
3018
3019 // Only continue checking for global regexps.
3020 if (!is_global) break;
3021
3022 // Continue from where the match ended, unless it was an empty match.
3023 int next = end;
3024 if (start == end) {
3025 next = end + 1;
3026 if (next > length) break;
3027 }
3028
3029 match = RegExpImpl::Exec(regexp_handle,
3030 subject_handle,
3031 next,
3032 last_match_info_handle);
3033 if (match.is_null()) {
3034 return Failure::Exception();
3035 }
3036 matched = !match->IsNull();
3037 } while (matched);
3038
3039 if (prev < length) {
3040 builder.AddSubjectSlice(prev, length);
3041 }
3042
3043 return *(builder.ToString());
3044}
3045
3046
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003047template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003048MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003049 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003050 String* subject,
3051 JSRegExp* regexp,
3052 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003053 ASSERT(subject->IsFlat());
3054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003055 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003056
3057 Handle<String> subject_handle(subject);
3058 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003059
3060 // Shortcut for simple non-regexp global replacements
3061 if (regexp_handle->GetFlags().is_global() &&
3062 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3063 Handle<String> empty_string_handle(HEAP->empty_string());
3064 if (subject_handle->HasOnlyAsciiChars()) {
3065 return StringReplaceStringWithString<SeqAsciiString>(
3066 isolate, subject_handle, regexp_handle, empty_string_handle);
3067 } else {
3068 return StringReplaceStringWithString<SeqTwoByteString>(
3069 isolate, subject_handle, regexp_handle, empty_string_handle);
3070 }
3071 }
3072
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003073 Handle<JSArray> last_match_info_handle(last_match_info);
3074 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3075 subject_handle,
3076 0,
3077 last_match_info_handle);
3078 if (match.is_null()) return Failure::Exception();
3079 if (match->IsNull()) return *subject_handle;
3080
3081 ASSERT(last_match_info_handle->HasFastElements());
3082
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003083 int start, end;
3084 {
3085 AssertNoAllocation match_info_array_is_not_in_a_handle;
3086 FixedArray* match_info_array =
3087 FixedArray::cast(last_match_info_handle->elements());
3088
3089 start = RegExpImpl::GetCapture(match_info_array, 0);
3090 end = RegExpImpl::GetCapture(match_info_array, 1);
3091 }
3092
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003093 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003094 int new_length = length - (end - start);
3095 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003096 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003097 }
3098 Handle<ResultSeqString> answer;
3099 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003100 answer = Handle<ResultSeqString>::cast(
3101 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003103 answer = Handle<ResultSeqString>::cast(
3104 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003105 }
3106
3107 // If the regexp isn't global, only match once.
3108 if (!regexp_handle->GetFlags().is_global()) {
3109 if (start > 0) {
3110 String::WriteToFlat(*subject_handle,
3111 answer->GetChars(),
3112 0,
3113 start);
3114 }
3115 if (end < length) {
3116 String::WriteToFlat(*subject_handle,
3117 answer->GetChars() + start,
3118 end,
3119 length);
3120 }
3121 return *answer;
3122 }
3123
3124 int prev = 0; // Index of end of last match.
3125 int next = 0; // Start of next search (prev unless last match was empty).
3126 int position = 0;
3127
3128 do {
3129 if (prev < start) {
3130 // Add substring subject[prev;start] to answer string.
3131 String::WriteToFlat(*subject_handle,
3132 answer->GetChars() + position,
3133 prev,
3134 start);
3135 position += start - prev;
3136 }
3137 prev = end;
3138 next = end;
3139 // Continue from where the match ended, unless it was an empty match.
3140 if (start == end) {
3141 next++;
3142 if (next > length) break;
3143 }
3144 match = RegExpImpl::Exec(regexp_handle,
3145 subject_handle,
3146 next,
3147 last_match_info_handle);
3148 if (match.is_null()) return Failure::Exception();
3149 if (match->IsNull()) break;
3150
3151 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003152 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003153 {
3154 AssertNoAllocation match_info_array_is_not_in_a_handle;
3155 FixedArray* match_info_array =
3156 FixedArray::cast(last_match_info_handle->elements());
3157 start = RegExpImpl::GetCapture(match_info_array, 0);
3158 end = RegExpImpl::GetCapture(match_info_array, 1);
3159 }
3160 } while (true);
3161
3162 if (prev < length) {
3163 // Add substring subject[prev;length] to answer string.
3164 String::WriteToFlat(*subject_handle,
3165 answer->GetChars() + position,
3166 prev,
3167 length);
3168 position += length - prev;
3169 }
3170
3171 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003172 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003173 }
3174
3175 // Shorten string and fill
3176 int string_size = ResultSeqString::SizeFor(position);
3177 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3178 int delta = allocated_string_size - string_size;
3179
3180 answer->set_length(position);
3181 if (delta == 0) return *answer;
3182
3183 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003184 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003185 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3186 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3187 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003188
3189 return *answer;
3190}
3191
3192
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003193RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003194 ASSERT(args.length() == 4);
3195
3196 CONVERT_CHECKED(String, subject, args[0]);
3197 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003198 Object* flat_subject;
3199 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3200 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3201 return maybe_flat_subject;
3202 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003203 }
3204 subject = String::cast(flat_subject);
3205 }
3206
3207 CONVERT_CHECKED(String, replacement, args[2]);
3208 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003209 Object* flat_replacement;
3210 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3211 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3212 return maybe_flat_replacement;
3213 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003214 }
3215 replacement = String::cast(flat_replacement);
3216 }
3217
3218 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3219 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3220
3221 ASSERT(last_match_info->HasFastElements());
3222
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003223 if (replacement->length() == 0) {
3224 if (subject->HasOnlyAsciiChars()) {
3225 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003226 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003227 } else {
3228 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003229 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003230 }
3231 }
3232
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003233 return StringReplaceRegExpWithString(isolate,
3234 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003235 regexp,
3236 replacement,
3237 last_match_info);
3238}
3239
3240
ager@chromium.org7c537e22008-10-16 08:43:32 +00003241// Perform string match of pattern on subject, starting at start index.
3242// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003243// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244int Runtime::StringMatch(Isolate* isolate,
3245 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003246 Handle<String> pat,
3247 int start_index) {
3248 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003250
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003251 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003252 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003253
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003254 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003255 if (start_index + pattern_length > subject_length) return -1;
3256
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003257 if (!sub->IsFlat()) FlattenString(sub);
3258 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003259
ager@chromium.org7c537e22008-10-16 08:43:32 +00003260 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003261 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003262 String::FlatContent seq_sub = sub->GetFlatContent();
3263 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003264
ager@chromium.org7c537e22008-10-16 08:43:32 +00003265 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003266 if (seq_pat.IsAscii()) {
3267 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3268 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003269 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003270 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003271 pat_vector,
3272 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003273 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003274 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003275 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003276 pat_vector,
3277 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003278 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003279 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3280 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003282 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003283 pat_vector,
3284 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003285 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003287 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003288 pat_vector,
3289 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003290}
3291
3292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003293RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003294 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003295 ASSERT(args.length() == 3);
3296
ager@chromium.org7c537e22008-10-16 08:43:32 +00003297 CONVERT_ARG_CHECKED(String, sub, 0);
3298 CONVERT_ARG_CHECKED(String, pat, 1);
3299
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003300 Object* index = args[2];
3301 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003302 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003303
ager@chromium.org870a0b62008-11-04 11:43:05 +00003304 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003305 int position =
3306 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003307 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003308}
3309
3310
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003311template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003312static int StringMatchBackwards(Vector<const schar> subject,
3313 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003314 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003315 int pattern_length = pattern.length();
3316 ASSERT(pattern_length >= 1);
3317 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003318
3319 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003320 for (int i = 0; i < pattern_length; i++) {
3321 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003322 if (c > String::kMaxAsciiCharCode) {
3323 return -1;
3324 }
3325 }
3326 }
3327
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003328 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003329 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003330 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003331 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003332 while (j < pattern_length) {
3333 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003334 break;
3335 }
3336 j++;
3337 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003338 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003339 return i;
3340 }
3341 }
3342 return -1;
3343}
3344
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003345RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003346 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003347 ASSERT(args.length() == 3);
3348
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003349 CONVERT_ARG_CHECKED(String, sub, 0);
3350 CONVERT_ARG_CHECKED(String, pat, 1);
3351
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003352 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003354 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003355
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003356 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003357 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003358
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003359 if (start_index + pat_length > sub_length) {
3360 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003361 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003362
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003363 if (pat_length == 0) {
3364 return Smi::FromInt(start_index);
3365 }
3366
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003367 if (!sub->IsFlat()) FlattenString(sub);
3368 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003369
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003370 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003371 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3372
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003373 String::FlatContent sub_content = sub->GetFlatContent();
3374 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003376 if (pat_content.IsAscii()) {
3377 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3378 if (sub_content.IsAscii()) {
3379 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003380 pat_vector,
3381 start_index);
3382 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003384 pat_vector,
3385 start_index);
3386 }
3387 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003388 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3389 if (sub_content.IsAscii()) {
3390 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003391 pat_vector,
3392 start_index);
3393 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003394 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003395 pat_vector,
3396 start_index);
3397 }
3398 }
3399
3400 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003401}
3402
3403
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003404RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003405 NoHandleAllocation ha;
3406 ASSERT(args.length() == 2);
3407
3408 CONVERT_CHECKED(String, str1, args[0]);
3409 CONVERT_CHECKED(String, str2, args[1]);
3410
3411 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003412 int str1_length = str1->length();
3413 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003414
3415 // Decide trivial cases without flattening.
3416 if (str1_length == 0) {
3417 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3418 return Smi::FromInt(-str2_length);
3419 } else {
3420 if (str2_length == 0) return Smi::FromInt(str1_length);
3421 }
3422
3423 int end = str1_length < str2_length ? str1_length : str2_length;
3424
3425 // No need to flatten if we are going to find the answer on the first
3426 // character. At this point we know there is at least one character
3427 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003428 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003429 if (d != 0) return Smi::FromInt(d);
3430
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003431 str1->TryFlatten();
3432 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003434 StringInputBuffer& buf1 =
3435 *isolate->runtime_state()->string_locale_compare_buf1();
3436 StringInputBuffer& buf2 =
3437 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003438
3439 buf1.Reset(str1);
3440 buf2.Reset(str2);
3441
3442 for (int i = 0; i < end; i++) {
3443 uint16_t char1 = buf1.GetNext();
3444 uint16_t char2 = buf2.GetNext();
3445 if (char1 != char2) return Smi::FromInt(char1 - char2);
3446 }
3447
3448 return Smi::FromInt(str1_length - str2_length);
3449}
3450
3451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003452RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003453 NoHandleAllocation ha;
3454 ASSERT(args.length() == 3);
3455
3456 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003457 int start, end;
3458 // We have a fast integer-only case here to avoid a conversion to double in
3459 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003460 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3461 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3462 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3463 start = from_number;
3464 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003465 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003466 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3467 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003468 start = FastD2I(from_number);
3469 end = FastD2I(to_number);
3470 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471 RUNTIME_ASSERT(end >= start);
3472 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003473 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003474 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003475 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476}
3477
3478
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003479RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003480 ASSERT_EQ(3, args.length());
3481
3482 CONVERT_ARG_CHECKED(String, subject, 0);
3483 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3484 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3485 HandleScope handles;
3486
3487 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3488
3489 if (match.is_null()) {
3490 return Failure::Exception();
3491 }
3492 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003493 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003494 }
3495 int length = subject->length();
3496
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003497 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003498 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003499 int start;
3500 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003501 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003502 {
3503 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003504 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003505 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3506 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3507 }
3508 offsets.Add(start);
3509 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003510 if (start == end) if (++end > length) break;
3511 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003512 if (match.is_null()) {
3513 return Failure::Exception();
3514 }
3515 } while (!match->IsNull());
3516 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003517 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003518 Handle<String> substring = isolate->factory()->
3519 NewSubString(subject, offsets.at(0), offsets.at(1));
3520 elements->set(0, *substring);
3521 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003522 int from = offsets.at(i * 2);
3523 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003524 Handle<String> substring = isolate->factory()->
3525 NewProperSubString(subject, from, to);
3526 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003527 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003528 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003529 result->set_length(Smi::FromInt(matches));
3530 return *result;
3531}
3532
3533
lrn@chromium.org25156de2010-04-06 13:10:27 +00003534// Two smis before and after the match, for very long strings.
3535const int kMaxBuilderEntriesPerRegExpMatch = 5;
3536
3537
3538static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3539 Handle<JSArray> last_match_info,
3540 int match_start,
3541 int match_end) {
3542 // Fill last_match_info with a single capture.
3543 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3544 AssertNoAllocation no_gc;
3545 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3546 RegExpImpl::SetLastCaptureCount(elements, 2);
3547 RegExpImpl::SetLastInput(elements, *subject);
3548 RegExpImpl::SetLastSubject(elements, *subject);
3549 RegExpImpl::SetCapture(elements, 0, match_start);
3550 RegExpImpl::SetCapture(elements, 1, match_end);
3551}
3552
3553
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003554template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003555static bool SearchStringMultiple(Isolate* isolate,
3556 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003557 Vector<const PatternChar> pattern,
3558 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003559 FixedArrayBuilder* builder,
3560 int* match_pos) {
3561 int pos = *match_pos;
3562 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003563 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003564 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003566 while (pos <= max_search_start) {
3567 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3568 *match_pos = pos;
3569 return false;
3570 }
3571 // Position of end of previous match.
3572 int match_end = pos + pattern_length;
3573 int new_pos = search.Search(subject, match_end);
3574 if (new_pos >= 0) {
3575 // A match.
3576 if (new_pos > match_end) {
3577 ReplacementStringBuilder::AddSubjectSlice(builder,
3578 match_end,
3579 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003580 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003581 pos = new_pos;
3582 builder->Add(pattern_string);
3583 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003584 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003585 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003586 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003587
lrn@chromium.org25156de2010-04-06 13:10:27 +00003588 if (pos < max_search_start) {
3589 ReplacementStringBuilder::AddSubjectSlice(builder,
3590 pos + pattern_length,
3591 subject_length);
3592 }
3593 *match_pos = pos;
3594 return true;
3595}
3596
3597
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003598static bool SearchStringMultiple(Isolate* isolate,
3599 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003600 Handle<String> pattern,
3601 Handle<JSArray> last_match_info,
3602 FixedArrayBuilder* builder) {
3603 ASSERT(subject->IsFlat());
3604 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003605
3606 // Treating as if a previous match was before first character.
3607 int match_pos = -pattern->length();
3608
3609 for (;;) { // Break when search complete.
3610 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3611 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003612 String::FlatContent subject_content = subject->GetFlatContent();
3613 String::FlatContent pattern_content = pattern->GetFlatContent();
3614 if (subject_content.IsAscii()) {
3615 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3616 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 if (SearchStringMultiple(isolate,
3618 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003619 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003620 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003621 builder,
3622 &match_pos)) break;
3623 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003624 if (SearchStringMultiple(isolate,
3625 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003626 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003627 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003628 builder,
3629 &match_pos)) break;
3630 }
3631 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003632 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3633 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003634 if (SearchStringMultiple(isolate,
3635 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003636 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003637 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003638 builder,
3639 &match_pos)) break;
3640 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 if (SearchStringMultiple(isolate,
3642 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003643 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003644 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003645 builder,
3646 &match_pos)) break;
3647 }
3648 }
3649 }
3650
3651 if (match_pos >= 0) {
3652 SetLastMatchInfoNoCaptures(subject,
3653 last_match_info,
3654 match_pos,
3655 match_pos + pattern->length());
3656 return true;
3657 }
3658 return false; // No matches at all.
3659}
3660
3661
3662static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003664 Handle<String> subject,
3665 Handle<JSRegExp> regexp,
3666 Handle<JSArray> last_match_array,
3667 FixedArrayBuilder* builder) {
3668 ASSERT(subject->IsFlat());
3669 int match_start = -1;
3670 int match_end = 0;
3671 int pos = 0;
3672 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3673 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3674
3675 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003676 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003677 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003678 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003679
3680 for (;;) { // Break on failure, return on exception.
3681 RegExpImpl::IrregexpResult result =
3682 RegExpImpl::IrregexpExecOnce(regexp,
3683 subject,
3684 pos,
3685 register_vector);
3686 if (result == RegExpImpl::RE_SUCCESS) {
3687 match_start = register_vector[0];
3688 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3689 if (match_end < match_start) {
3690 ReplacementStringBuilder::AddSubjectSlice(builder,
3691 match_end,
3692 match_start);
3693 }
3694 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003695 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003696 if (!first) {
3697 builder->Add(*isolate->factory()->NewProperSubString(subject,
3698 match_start,
3699 match_end));
3700 } else {
3701 builder->Add(*isolate->factory()->NewSubString(subject,
3702 match_start,
3703 match_end));
3704 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003705 if (match_start != match_end) {
3706 pos = match_end;
3707 } else {
3708 pos = match_end + 1;
3709 if (pos > subject_length) break;
3710 }
3711 } else if (result == RegExpImpl::RE_FAILURE) {
3712 break;
3713 } else {
3714 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3715 return result;
3716 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003717 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003718 }
3719
3720 if (match_start >= 0) {
3721 if (match_end < subject_length) {
3722 ReplacementStringBuilder::AddSubjectSlice(builder,
3723 match_end,
3724 subject_length);
3725 }
3726 SetLastMatchInfoNoCaptures(subject,
3727 last_match_array,
3728 match_start,
3729 match_end);
3730 return RegExpImpl::RE_SUCCESS;
3731 } else {
3732 return RegExpImpl::RE_FAILURE; // No matches at all.
3733 }
3734}
3735
3736
3737static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003738 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003739 Handle<String> subject,
3740 Handle<JSRegExp> regexp,
3741 Handle<JSArray> last_match_array,
3742 FixedArrayBuilder* builder) {
3743
3744 ASSERT(subject->IsFlat());
3745 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3746 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3747
3748 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003749 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003750
3751 RegExpImpl::IrregexpResult result =
3752 RegExpImpl::IrregexpExecOnce(regexp,
3753 subject,
3754 0,
3755 register_vector);
3756
3757 int capture_count = regexp->CaptureCount();
3758 int subject_length = subject->length();
3759
3760 // Position to search from.
3761 int pos = 0;
3762 // End of previous match. Differs from pos if match was empty.
3763 int match_end = 0;
3764 if (result == RegExpImpl::RE_SUCCESS) {
3765 // Need to keep a copy of the previous match for creating last_match_info
3766 // at the end, so we have two vectors that we swap between.
3767 OffsetsVector registers2(required_registers);
3768 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003769 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003770 do {
3771 int match_start = register_vector[0];
3772 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3773 if (match_end < match_start) {
3774 ReplacementStringBuilder::AddSubjectSlice(builder,
3775 match_end,
3776 match_start);
3777 }
3778 match_end = register_vector[1];
3779
3780 {
3781 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003782 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003783 // Arguments array to replace function is match, captures, index and
3784 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 Handle<FixedArray> elements =
3786 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003787 Handle<String> match;
3788 if (!first) {
3789 match = isolate->factory()->NewProperSubString(subject,
3790 match_start,
3791 match_end);
3792 } else {
3793 match = isolate->factory()->NewSubString(subject,
3794 match_start,
3795 match_end);
3796 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003797 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003798 for (int i = 1; i <= capture_count; i++) {
3799 int start = register_vector[i * 2];
3800 if (start >= 0) {
3801 int end = register_vector[i * 2 + 1];
3802 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003803 Handle<String> substring;
3804 if (!first) {
3805 substring = isolate->factory()->NewProperSubString(subject,
3806 start,
3807 end);
3808 } else {
3809 substring = isolate->factory()->NewSubString(subject, start, end);
3810 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003811 elements->set(i, *substring);
3812 } else {
3813 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003814 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003815 }
3816 }
3817 elements->set(capture_count + 1, Smi::FromInt(match_start));
3818 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003819 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003820 }
3821 // Swap register vectors, so the last successful match is in
3822 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003823 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003824 prev_register_vector = register_vector;
3825 register_vector = tmp;
3826
3827 if (match_end > match_start) {
3828 pos = match_end;
3829 } else {
3830 pos = match_end + 1;
3831 if (pos > subject_length) {
3832 break;
3833 }
3834 }
3835
3836 result = RegExpImpl::IrregexpExecOnce(regexp,
3837 subject,
3838 pos,
3839 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003840 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003841 } while (result == RegExpImpl::RE_SUCCESS);
3842
3843 if (result != RegExpImpl::RE_EXCEPTION) {
3844 // Finished matching, with at least one match.
3845 if (match_end < subject_length) {
3846 ReplacementStringBuilder::AddSubjectSlice(builder,
3847 match_end,
3848 subject_length);
3849 }
3850
3851 int last_match_capture_count = (capture_count + 1) * 2;
3852 int last_match_array_size =
3853 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3854 last_match_array->EnsureSize(last_match_array_size);
3855 AssertNoAllocation no_gc;
3856 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3857 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3858 RegExpImpl::SetLastSubject(elements, *subject);
3859 RegExpImpl::SetLastInput(elements, *subject);
3860 for (int i = 0; i < last_match_capture_count; i++) {
3861 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3862 }
3863 return RegExpImpl::RE_SUCCESS;
3864 }
3865 }
3866 // No matches at all, return failure or exception result directly.
3867 return result;
3868}
3869
3870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003871RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003872 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003873 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003874
3875 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003876 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003877 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3878 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3879 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3880
3881 ASSERT(last_match_info->HasFastElements());
3882 ASSERT(regexp->GetFlags().is_global());
3883 Handle<FixedArray> result_elements;
3884 if (result_array->HasFastElements()) {
3885 result_elements =
3886 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003887 }
3888 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003889 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003890 }
3891 FixedArrayBuilder builder(result_elements);
3892
3893 if (regexp->TypeTag() == JSRegExp::ATOM) {
3894 Handle<String> pattern(
3895 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003896 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003897 if (SearchStringMultiple(isolate, subject, pattern,
3898 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003899 return *builder.ToJSArray(result_array);
3900 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003901 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003902 }
3903
3904 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3905
3906 RegExpImpl::IrregexpResult result;
3907 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003908 result = SearchRegExpNoCaptureMultiple(isolate,
3909 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003910 regexp,
3911 last_match_info,
3912 &builder);
3913 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003914 result = SearchRegExpMultiple(isolate,
3915 subject,
3916 regexp,
3917 last_match_info,
3918 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003919 }
3920 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003921 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003922 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3923 return Failure::Exception();
3924}
3925
3926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003927RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 NoHandleAllocation ha;
3929 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003930 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003931 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003933 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003934 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003935 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003936 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003937 // Character array used for conversion.
3938 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003939 return isolate->heap()->
3940 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003941 }
3942 }
3943
3944 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003945 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003946 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003947 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003948 }
3949 if (isinf(value)) {
3950 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003951 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003952 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003953 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003954 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003955 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003956 MaybeObject* result =
3957 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003958 DeleteArray(str);
3959 return result;
3960}
3961
3962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003963RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003964 NoHandleAllocation ha;
3965 ASSERT(args.length() == 2);
3966
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003967 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003968 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003969 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970 }
3971 if (isinf(value)) {
3972 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003973 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003974 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003975 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003976 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003977 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 int f = FastD2I(f_number);
3979 RUNTIME_ASSERT(f >= 0);
3980 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003981 MaybeObject* res =
3982 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003983 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003984 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003985}
3986
3987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003988RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003989 NoHandleAllocation ha;
3990 ASSERT(args.length() == 2);
3991
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003992 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003993 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003994 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003995 }
3996 if (isinf(value)) {
3997 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003998 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003999 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004000 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004001 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004002 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 int f = FastD2I(f_number);
4004 RUNTIME_ASSERT(f >= -1 && f <= 20);
4005 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 MaybeObject* res =
4007 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010}
4011
4012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004013RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 NoHandleAllocation ha;
4015 ASSERT(args.length() == 2);
4016
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004017 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004018 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004019 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 }
4021 if (isinf(value)) {
4022 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004023 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004025 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004026 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004027 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004028 int f = FastD2I(f_number);
4029 RUNTIME_ASSERT(f >= 1 && f <= 21);
4030 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004031 MaybeObject* res =
4032 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004033 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004034 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004035}
4036
4037
4038// Returns a single character string where first character equals
4039// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004040static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004041 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004042 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004043 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004044 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004045 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004046 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047}
4048
4049
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004050MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4051 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004052 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 // Handle [] indexing on Strings
4054 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004055 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4056 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 }
4058
4059 // Handle [] indexing on String objects
4060 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004061 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4062 Handle<Object> result =
4063 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4064 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 }
4066
4067 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004068 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004069 return prototype->GetElement(index);
4070 }
4071
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004072 return GetElement(object, index);
4073}
4074
4075
lrn@chromium.org303ada72010-10-27 09:33:13 +00004076MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 return object->GetElement(index);
4078}
4079
4080
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004081MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4082 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004083 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004084 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004085
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004086 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004087 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004088 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004089 isolate->factory()->NewTypeError("non_object_property_load",
4090 HandleVector(args, 2));
4091 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004092 }
4093
4094 // Check if the given key is an array index.
4095 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004096 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004097 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004098 }
4099
4100 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004101 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004103 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004104 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 bool has_pending_exception = false;
4106 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004107 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004108 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004109 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110 }
4111
ager@chromium.org32912102009-01-16 10:38:43 +00004112 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004113 // the element if so.
4114 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004115 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004117 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 }
4119}
4120
4121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004122RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004123 NoHandleAllocation ha;
4124 ASSERT(args.length() == 2);
4125
4126 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004127 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004129 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004130}
4131
4132
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004133// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004134RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004135 NoHandleAllocation ha;
4136 ASSERT(args.length() == 2);
4137
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004138 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004139 // itself.
4140 //
4141 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004142 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004143 // global proxy object never has properties. This is the case
4144 // because the global proxy object forwards everything to its hidden
4145 // prototype including local lookups.
4146 //
4147 // Additionally, we need to make sure that we do not cache results
4148 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004149 if (args[0]->IsJSObject() &&
4150 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00004151 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004152 args[1]->IsString()) {
4153 JSObject* receiver = JSObject::cast(args[0]);
4154 String* key = String::cast(args[1]);
4155 if (receiver->HasFastProperties()) {
4156 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004157 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004158 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4159 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004160 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004161 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004162 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004163 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004164 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004165 LookupResult result;
4166 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00004167 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004168 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004169 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004170 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004171 }
4172 } else {
4173 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00004174 StringDictionary* dictionary = receiver->property_dictionary();
4175 int entry = dictionary->FindEntry(key);
4176 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004177 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00004178 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00004179 if (!receiver->IsGlobalObject()) return value;
4180 value = JSGlobalPropertyCell::cast(value)->value();
4181 if (!value->IsTheHole()) return value;
4182 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004183 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004184 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004185 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4186 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004188 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004189 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004190 if (index >= 0 && index < str->length()) {
4191 Handle<Object> result = GetCharAt(str, index);
4192 return *result;
4193 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004194 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004195
4196 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004197 return Runtime::GetObjectProperty(isolate,
4198 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004199 args.at<Object>(1));
4200}
4201
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004202// Implements part of 8.12.9 DefineOwnProperty.
4203// There are 3 cases that lead here:
4204// Step 4b - define a new accessor property.
4205// Steps 9c & 12 - replace an existing data property with an accessor property.
4206// Step 12 - update an existing accessor property with an accessor or generic
4207// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004208RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004209 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004210 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004211 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4212 CONVERT_CHECKED(String, name, args[1]);
4213 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004214 Object* fun = args[3];
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004215 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004216 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4217 int unchecked = flag_attr->value();
4218 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4219 RUNTIME_ASSERT(!obj->IsNull());
4220 LookupResult result;
4221 obj->LocalLookupRealNamedProperty(name, &result);
4222
4223 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4224 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4225 // delete it to avoid running into trouble in DefineAccessor, which
4226 // handles this incorrectly if the property is readonly (does nothing)
4227 if (result.IsProperty() &&
4228 (result.type() == FIELD || result.type() == NORMAL
4229 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004230 Object* ok;
4231 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004232 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004233 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4234 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004235 }
4236 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4237}
4238
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004239// Implements part of 8.12.9 DefineOwnProperty.
4240// There are 3 cases that lead here:
4241// Step 4a - define a new data property.
4242// Steps 9b & 12 - replace an existing accessor property with a data property.
4243// Step 12 - update an existing data property with a data or generic
4244// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004245RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004246 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004247 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004248 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4249 CONVERT_ARG_CHECKED(String, name, 1);
4250 Handle<Object> obj_value = args.at<Object>(2);
4251
4252 CONVERT_CHECKED(Smi, flag, args[3]);
4253 int unchecked = flag->value();
4254 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4255
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004256 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4257
4258 // Check if this is an element.
4259 uint32_t index;
4260 bool is_element = name->AsArrayIndex(&index);
4261
4262 // Special case for elements if any of the flags are true.
4263 // If elements are in fast case we always implicitly assume that:
4264 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4265 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4266 is_element) {
4267 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004268 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004269 // We do not need to do access checks here since these has already
4270 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004271 Handle<Object> proto(js_object->GetPrototype());
4272 // If proxy is detached, ignore the assignment. Alternatively,
4273 // we could throw an exception.
4274 if (proto->IsNull()) return *obj_value;
4275 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004276 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004277
4278 // Don't allow element properties to be redefined on objects with external
4279 // array elements.
4280 if (js_object->HasExternalArrayElements()) {
4281 Handle<Object> args[2] = { js_object, name };
4282 Handle<Object> error =
4283 isolate->factory()->NewTypeError("redef_external_array_element",
4284 HandleVector(args, 2));
4285 return isolate->Throw(*error);
4286 }
4287
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004288 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004289 // Make sure that we never go back to fast case.
4290 dictionary->set_requires_slow_elements();
4291 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004292 Handle<NumberDictionary> extended_dictionary =
4293 NumberDictionarySet(dictionary, index, obj_value, details);
4294 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004295 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004296 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4297 } else {
4298 js_object->set_elements(*extended_dictionary);
4299 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004300 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004301 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004302 }
4303
ager@chromium.org5c838252010-02-19 08:53:10 +00004304 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004305 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004306
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004307 // To be compatible with safari we do not change the value on API objects
4308 // in defineProperty. Firefox disagrees here, and actually changes the value.
4309 if (result.IsProperty() &&
4310 (result.type() == CALLBACKS) &&
4311 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004313 }
4314
ager@chromium.org5c838252010-02-19 08:53:10 +00004315 // Take special care when attributes are different and there is already
4316 // a property. For simplicity we normalize the property which enables us
4317 // to not worry about changing the instance_descriptor and creating a new
4318 // map. The current version of SetObjectProperty does not handle attributes
4319 // correctly in the case where a property is a field and is reset with
4320 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004321 if (result.IsProperty() &&
4322 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004323 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004324 if (js_object->IsJSGlobalProxy()) {
4325 // Since the result is a property, the prototype will exist so
4326 // we don't have to check for null.
4327 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004328 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004329 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004330 // Use IgnoreAttributes version since a readonly property may be
4331 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004332 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4333 *obj_value,
4334 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004335 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004336
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 return Runtime::ForceSetObjectProperty(isolate,
4338 js_object,
4339 name,
4340 obj_value,
4341 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004342}
4343
4344
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004345// Special case for elements if any of the flags are true.
4346// If elements are in fast case we always implicitly assume that:
4347// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4348static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4349 Handle<JSObject> js_object,
4350 uint32_t index,
4351 Handle<Object> value,
4352 PropertyAttributes attr) {
4353 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004354 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004355 // Make sure that we never go back to fast case.
4356 dictionary->set_requires_slow_elements();
4357 PropertyDetails details = PropertyDetails(attr, NORMAL);
4358 Handle<NumberDictionary> extended_dictionary =
4359 NumberDictionarySet(dictionary, index, value, details);
4360 if (*extended_dictionary != *dictionary) {
4361 js_object->set_elements(*extended_dictionary);
4362 }
4363 return *value;
4364}
4365
4366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004367MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4368 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004369 Handle<Object> key,
4370 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004371 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004372 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004373 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004374
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004375 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004376 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004377 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004378 isolate->factory()->NewTypeError("non_object_property_store",
4379 HandleVector(args, 2));
4380 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004381 }
4382
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004383 if (object->IsJSProxy()) {
4384 bool has_pending_exception = false;
4385 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4386 if (has_pending_exception) return Failure::Exception();
4387 return JSProxy::cast(*object)->SetProperty(
4388 String::cast(*name), *value, attr, strict_mode);
4389 }
4390
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004391 // If the object isn't a JavaScript object, we ignore the store.
4392 if (!object->IsJSObject()) return *value;
4393
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004394 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4395
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004396 // Check if the given key is an array index.
4397 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004398 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004399 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4400 // of a string using [] notation. We need to support this too in
4401 // JavaScript.
4402 // In the case of a String object we just need to redirect the assignment to
4403 // the underlying string if the index is in range. Since the underlying
4404 // string does nothing with the assignment then we can ignore such
4405 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004406 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004409
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004410 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4411 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4412 }
4413
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004414 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004415 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004416 return *value;
4417 }
4418
4419 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004420 Handle<Object> result;
4421 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004422 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4423 return NormalizeObjectSetElement(isolate,
4424 js_object,
4425 index,
4426 value,
4427 attr);
4428 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004429 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004430 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004431 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004432 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004433 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004434 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004435 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004436 return *value;
4437 }
4438
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004439 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440 bool has_pending_exception = false;
4441 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4442 if (has_pending_exception) return Failure::Exception();
4443 Handle<String> name = Handle<String>::cast(converted);
4444
4445 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004446 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004447 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004448 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004449 }
4450}
4451
4452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004453MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4454 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004455 Handle<Object> key,
4456 Handle<Object> value,
4457 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004458 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004459
4460 // Check if the given key is an array index.
4461 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004462 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004463 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4464 // of a string using [] notation. We need to support this too in
4465 // JavaScript.
4466 // In the case of a String object we just need to redirect the assignment to
4467 // the underlying string if the index is in range. Since the underlying
4468 // string does nothing with the assignment then we can ignore such
4469 // assignments.
4470 if (js_object->IsStringObjectWithCharacterAt(index)) {
4471 return *value;
4472 }
4473
whesse@chromium.org7b260152011-06-20 15:33:18 +00004474 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004475 }
4476
4477 if (key->IsString()) {
4478 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004479 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004480 } else {
4481 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004482 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004483 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4484 *value,
4485 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004486 }
4487 }
4488
4489 // Call-back into JavaScript to convert the key to a string.
4490 bool has_pending_exception = false;
4491 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4492 if (has_pending_exception) return Failure::Exception();
4493 Handle<String> name = Handle<String>::cast(converted);
4494
4495 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004496 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004497 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004498 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004499 }
4500}
4501
4502
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004503MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004504 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004505 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004506 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004507
4508 // Check if the given key is an array index.
4509 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004510 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004511 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4512 // characters of a string using [] notation. In the case of a
4513 // String object we just need to redirect the deletion to the
4514 // underlying string if the index is in range. Since the
4515 // underlying string does nothing with the deletion, we can ignore
4516 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004517 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004518 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004519 }
4520
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004521 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004522 }
4523
4524 Handle<String> key_string;
4525 if (key->IsString()) {
4526 key_string = Handle<String>::cast(key);
4527 } else {
4528 // Call-back into JavaScript to convert the key to a string.
4529 bool has_pending_exception = false;
4530 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4531 if (has_pending_exception) return Failure::Exception();
4532 key_string = Handle<String>::cast(converted);
4533 }
4534
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004535 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004536 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004537}
4538
4539
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004540RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004541 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004542 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543
4544 Handle<Object> object = args.at<Object>(0);
4545 Handle<Object> key = args.at<Object>(1);
4546 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004547 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004548 RUNTIME_ASSERT(
4549 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004551 PropertyAttributes attributes =
4552 static_cast<PropertyAttributes>(unchecked_attributes);
4553
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004554 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004555 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004556 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004557 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4558 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004559 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004560 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004561
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004562 return Runtime::SetObjectProperty(isolate,
4563 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004564 key,
4565 value,
4566 attributes,
4567 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004568}
4569
4570
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004571// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004572// This is used to decide if we should transform null and undefined
4573// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004575 NoHandleAllocation ha;
4576 RUNTIME_ASSERT(args.length() == 1);
4577
4578 Handle<Object> object = args.at<Object>(0);
4579
4580 if (object->IsJSFunction()) {
4581 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004582 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004583 }
4584 return isolate->heap()->undefined_value();
4585}
4586
4587
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004588// Set a local property, even if it is READ_ONLY. If the property does not
4589// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004590RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004591 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004592 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 CONVERT_CHECKED(JSObject, object, args[0]);
4594 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004595 // Compute attributes.
4596 PropertyAttributes attributes = NONE;
4597 if (args.length() == 4) {
4598 CONVERT_CHECKED(Smi, value_obj, args[3]);
4599 int unchecked_value = value_obj->value();
4600 // Only attribute bits should be set.
4601 RUNTIME_ASSERT(
4602 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4603 attributes = static_cast<PropertyAttributes>(unchecked_value);
4604 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004606 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004607 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608}
4609
4610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004611RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004612 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004613 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004614
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004615 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004616 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004617 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004618 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004619 ? JSReceiver::STRICT_DELETION
4620 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004621}
4622
4623
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004624static Object* HasLocalPropertyImplementation(Isolate* isolate,
4625 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004626 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004627 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004628 // Handle hidden prototypes. If there's a hidden prototype above this thing
4629 // then we have to check it for properties, because they are supposed to
4630 // look like they are on this object.
4631 Handle<Object> proto(object->GetPrototype());
4632 if (proto->IsJSObject() &&
4633 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004634 return HasLocalPropertyImplementation(isolate,
4635 Handle<JSObject>::cast(proto),
4636 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004637 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004638 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004639}
4640
4641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004642RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004643 NoHandleAllocation ha;
4644 ASSERT(args.length() == 2);
4645 CONVERT_CHECKED(String, key, args[1]);
4646
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004647 uint32_t index;
4648 const bool key_is_array_index = key->AsArrayIndex(&index);
4649
ager@chromium.org9085a012009-05-11 19:22:57 +00004650 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004651 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004652 if (obj->IsJSObject()) {
4653 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004654 // Fast case: either the key is a real named property or it is not
4655 // an array index and there are no interceptors or hidden
4656 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004657 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004658 Map* map = object->map();
4659 if (!key_is_array_index &&
4660 !map->has_named_interceptor() &&
4661 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4662 return isolate->heap()->false_value();
4663 }
4664 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004665 HandleScope scope(isolate);
4666 return HasLocalPropertyImplementation(isolate,
4667 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004668 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004669 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004670 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004671 String* string = String::cast(obj);
4672 if (index < static_cast<uint32_t>(string->length())) {
4673 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004674 }
4675 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004676 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677}
4678
4679
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004680RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 NoHandleAllocation na;
4682 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004683 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4684 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004686 bool result = receiver->HasProperty(key);
4687 if (isolate->has_pending_exception()) return Failure::Exception();
4688 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689}
4690
4691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693 NoHandleAllocation na;
4694 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004695 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4696 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004698 bool result = receiver->HasElement(index->value());
4699 if (isolate->has_pending_exception()) return Failure::Exception();
4700 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701}
4702
4703
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004704RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 NoHandleAllocation ha;
4706 ASSERT(args.length() == 2);
4707
4708 CONVERT_CHECKED(JSObject, object, args[0]);
4709 CONVERT_CHECKED(String, key, args[1]);
4710
4711 uint32_t index;
4712 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004713 JSObject::LocalElementType type = object->HasLocalElement(index);
4714 switch (type) {
4715 case JSObject::UNDEFINED_ELEMENT:
4716 case JSObject::STRING_CHARACTER_ELEMENT:
4717 return isolate->heap()->false_value();
4718 case JSObject::INTERCEPTED_ELEMENT:
4719 case JSObject::FAST_ELEMENT:
4720 return isolate->heap()->true_value();
4721 case JSObject::DICTIONARY_ELEMENT: {
4722 if (object->IsJSGlobalProxy()) {
4723 Object* proto = object->GetPrototype();
4724 if (proto->IsNull()) {
4725 return isolate->heap()->false_value();
4726 }
4727 ASSERT(proto->IsJSGlobalObject());
4728 object = JSObject::cast(proto);
4729 }
4730 FixedArray* elements = FixedArray::cast(object->elements());
4731 NumberDictionary* dictionary = NULL;
4732 if (elements->map() ==
4733 isolate->heap()->non_strict_arguments_elements_map()) {
4734 dictionary = NumberDictionary::cast(elements->get(1));
4735 } else {
4736 dictionary = NumberDictionary::cast(elements);
4737 }
4738 int entry = dictionary->FindEntry(index);
4739 ASSERT(entry != NumberDictionary::kNotFound);
4740 PropertyDetails details = dictionary->DetailsAt(entry);
4741 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4742 }
4743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004744 }
4745
ager@chromium.org870a0b62008-11-04 11:43:05 +00004746 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004748}
4749
4750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004751RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004752 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004753 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004754 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004755 return *GetKeysFor(object);
4756}
4757
4758
4759// Returns either a FixedArray as Runtime_GetPropertyNames,
4760// or, if the given object has an enum cache that contains
4761// all enumerable properties of the object and its prototypes
4762// have none, the map of the object. This is used to speed up
4763// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004764RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765 ASSERT(args.length() == 1);
4766
4767 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4768
4769 if (raw_object->IsSimpleEnum()) return raw_object->map();
4770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004771 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004772 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004773 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4774 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004775
4776 // Test again, since cache may have been built by preceding call.
4777 if (object->IsSimpleEnum()) return object->map();
4778
4779 return *content;
4780}
4781
4782
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004783// Find the length of the prototype chain that is to to handled as one. If a
4784// prototype object is hidden it is to be viewed as part of the the object it
4785// is prototype for.
4786static int LocalPrototypeChainLength(JSObject* obj) {
4787 int count = 1;
4788 Object* proto = obj->GetPrototype();
4789 while (proto->IsJSObject() &&
4790 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4791 count++;
4792 proto = JSObject::cast(proto)->GetPrototype();
4793 }
4794 return count;
4795}
4796
4797
4798// Return the names of the local named properties.
4799// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004800RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004801 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004802 ASSERT(args.length() == 1);
4803 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004804 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004805 }
4806 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4807
4808 // Skip the global proxy as it has no properties and always delegates to the
4809 // real global object.
4810 if (obj->IsJSGlobalProxy()) {
4811 // Only collect names if access is permitted.
4812 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004813 !isolate->MayNamedAccess(*obj,
4814 isolate->heap()->undefined_value(),
4815 v8::ACCESS_KEYS)) {
4816 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4817 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004818 }
4819 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4820 }
4821
4822 // Find the number of objects making up this.
4823 int length = LocalPrototypeChainLength(*obj);
4824
4825 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004826 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004827 int total_property_count = 0;
4828 Handle<JSObject> jsproto = obj;
4829 for (int i = 0; i < length; i++) {
4830 // Only collect names if access is permitted.
4831 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004832 !isolate->MayNamedAccess(*jsproto,
4833 isolate->heap()->undefined_value(),
4834 v8::ACCESS_KEYS)) {
4835 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4836 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004837 }
4838 int n;
4839 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4840 local_property_count[i] = n;
4841 total_property_count += n;
4842 if (i < length - 1) {
4843 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4844 }
4845 }
4846
4847 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004848 Handle<FixedArray> names =
4849 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004850
4851 // Get the property names.
4852 jsproto = obj;
4853 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004854 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004855 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004856 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4857 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004858 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004859 proto_with_hidden_properties++;
4860 }
4861 if (i < length - 1) {
4862 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4863 }
4864 }
4865
4866 // Filter out name of hidden propeties object.
4867 if (proto_with_hidden_properties > 0) {
4868 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004869 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004870 names->length() - proto_with_hidden_properties);
4871 int dest_pos = 0;
4872 for (int i = 0; i < total_property_count; i++) {
4873 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004874 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004875 continue;
4876 }
4877 names->set(dest_pos++, name);
4878 }
4879 }
4880
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004881 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004882}
4883
4884
4885// Return the names of the local indexed properties.
4886// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004887RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004888 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004889 ASSERT(args.length() == 1);
4890 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004892 }
4893 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4894
4895 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004896 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004897 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004898 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004899}
4900
4901
4902// Return information on whether an object has a named or indexed interceptor.
4903// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004904RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004905 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004906 ASSERT(args.length() == 1);
4907 if (!args[0]->IsJSObject()) {
4908 return Smi::FromInt(0);
4909 }
4910 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4911
4912 int result = 0;
4913 if (obj->HasNamedInterceptor()) result |= 2;
4914 if (obj->HasIndexedInterceptor()) result |= 1;
4915
4916 return Smi::FromInt(result);
4917}
4918
4919
4920// Return property names from named interceptor.
4921// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004922RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004924 ASSERT(args.length() == 1);
4925 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4926
4927 if (obj->HasNamedInterceptor()) {
4928 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4929 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4930 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004931 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004932}
4933
4934
4935// Return element names from indexed interceptor.
4936// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004937RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004938 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004939 ASSERT(args.length() == 1);
4940 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4941
4942 if (obj->HasIndexedInterceptor()) {
4943 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4944 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4945 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004946 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004947}
4948
4949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004950RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004951 ASSERT_EQ(args.length(), 1);
4952 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004953 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004954 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004955
4956 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004957 // Do access checks before going to the global object.
4958 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004959 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004960 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004961 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4962 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004963 }
4964
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004965 Handle<Object> proto(object->GetPrototype());
4966 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004967 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004968 object = Handle<JSObject>::cast(proto);
4969 }
4970
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004971 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4972 LOCAL_ONLY);
4973 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4974 // property array and since the result is mutable we have to create
4975 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004976 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004978 for (int i = 0; i < length; i++) {
4979 Object* entry = contents->get(i);
4980 if (entry->IsString()) {
4981 copy->set(i, entry);
4982 } else {
4983 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 HandleScope scope(isolate);
4985 Handle<Object> entry_handle(entry, isolate);
4986 Handle<Object> entry_str =
4987 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004988 copy->set(i, *entry_str);
4989 }
4990 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004991 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004992}
4993
4994
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004995RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004996 NoHandleAllocation ha;
4997 ASSERT(args.length() == 1);
4998
4999 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005000 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005001 it.AdvanceToArgumentsFrame();
5002 JavaScriptFrame* frame = it.frame();
5003
5004 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005005 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006
5007 // Try to convert the key to an index. If successful and within
5008 // index return the the argument from the frame.
5009 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005010 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 return frame->GetParameter(index);
5012 }
5013
5014 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005015 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005016 bool exception = false;
5017 Handle<Object> converted =
5018 Execution::ToString(args.at<Object>(0), &exception);
5019 if (exception) return Failure::Exception();
5020 Handle<String> key = Handle<String>::cast(converted);
5021
5022 // Try to convert the string key into an array index.
5023 if (key->AsArrayIndex(&index)) {
5024 if (index < n) {
5025 return frame->GetParameter(index);
5026 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005027 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005028 }
5029 }
5030
5031 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005032 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5033 if (key->Equals(isolate->heap()->callee_symbol())) {
5034 Object* function = frame->function();
5035 if (function->IsJSFunction() &&
5036 JSFunction::cast(function)->shared()->strict_mode()) {
5037 return isolate->Throw(*isolate->factory()->NewTypeError(
5038 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5039 }
5040 return function;
5041 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005042
5043 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005044 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005045}
5046
5047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005048RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005049 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005050
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005051 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005052 Handle<Object> object = args.at<Object>(0);
5053 if (object->IsJSObject()) {
5054 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00005055 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005056 MaybeObject* ok = js_object->TransformToFastProperties(0);
5057 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00005058 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005059 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005060 return *object;
5061}
5062
5063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005064RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005065 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00005066
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005067 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005068 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00005069 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005070 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005071 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00005072 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005073 return *object;
5074}
5075
5076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005077RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005078 NoHandleAllocation ha;
5079 ASSERT(args.length() == 1);
5080
5081 return args[0]->ToBoolean();
5082}
5083
5084
5085// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5086// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005087RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005088 NoHandleAllocation ha;
5089
5090 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005091 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005092 HeapObject* heap_obj = HeapObject::cast(obj);
5093
5094 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005095 if (heap_obj->map()->is_undetectable()) {
5096 return isolate->heap()->undefined_symbol();
5097 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005098
5099 InstanceType instance_type = heap_obj->map()->instance_type();
5100 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005101 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005102 }
5103
5104 switch (instance_type) {
5105 case ODDBALL_TYPE:
5106 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005107 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 }
5109 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005110 return FLAG_harmony_typeof
5111 ? isolate->heap()->null_symbol()
5112 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005113 }
5114 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005115 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005116 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005117 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005118 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005119 default:
5120 // For any kind of object not handled above, the spec rule for
5121 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005122 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005123 }
5124}
5125
5126
lrn@chromium.org25156de2010-04-06 13:10:27 +00005127static bool AreDigits(const char*s, int from, int to) {
5128 for (int i = from; i < to; i++) {
5129 if (s[i] < '0' || s[i] > '9') return false;
5130 }
5131
5132 return true;
5133}
5134
5135
5136static int ParseDecimalInteger(const char*s, int from, int to) {
5137 ASSERT(to - from < 10); // Overflow is not possible.
5138 ASSERT(from < to);
5139 int d = s[from] - '0';
5140
5141 for (int i = from + 1; i < to; i++) {
5142 d = 10 * d + (s[i] - '0');
5143 }
5144
5145 return d;
5146}
5147
5148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005149RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005150 NoHandleAllocation ha;
5151 ASSERT(args.length() == 1);
5152 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005153 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005154
5155 // Fast case: short integer or some sorts of junk values.
5156 int len = subject->length();
5157 if (subject->IsSeqAsciiString()) {
5158 if (len == 0) return Smi::FromInt(0);
5159
5160 char const* data = SeqAsciiString::cast(subject)->GetChars();
5161 bool minus = (data[0] == '-');
5162 int start_pos = (minus ? 1 : 0);
5163
5164 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005165 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005166 } else if (data[start_pos] > '9') {
5167 // Fast check for a junk value. A valid string may start from a
5168 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5169 // the 'I' character ('Infinity'). All of that have codes not greater than
5170 // '9' except 'I'.
5171 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005172 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005173 }
5174 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5175 // The maximal/minimal smi has 10 digits. If the string has less digits we
5176 // know it will fit into the smi-data type.
5177 int d = ParseDecimalInteger(data, start_pos, len);
5178 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005179 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005180 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005181 } else if (!subject->HasHashCode() &&
5182 len <= String::kMaxArrayIndexSize &&
5183 (len == 1 || data[0] != '0')) {
5184 // String hash is not calculated yet but all the data are present.
5185 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005186 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005187#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005188 subject->Hash(); // Force hash calculation.
5189 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5190 static_cast<int>(hash));
5191#endif
5192 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005193 }
5194 return Smi::FromInt(d);
5195 }
5196 }
5197
5198 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005199 return isolate->heap()->NumberFromDouble(
5200 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005201}
5202
5203
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005204RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005205 NoHandleAllocation ha;
5206 ASSERT(args.length() == 1);
5207
5208 CONVERT_CHECKED(JSArray, codes, args[0]);
5209 int length = Smi::cast(codes->length())->value();
5210
5211 // Check if the string can be ASCII.
5212 int i;
5213 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005214 Object* element;
5215 { MaybeObject* maybe_element = codes->GetElement(i);
5216 // We probably can't get an exception here, but just in order to enforce
5217 // the checking of inputs in the runtime calls we check here.
5218 if (!maybe_element->ToObject(&element)) return maybe_element;
5219 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005220 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5221 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5222 break;
5223 }
5224
lrn@chromium.org303ada72010-10-27 09:33:13 +00005225 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005226 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005227 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005230 }
5231
lrn@chromium.org303ada72010-10-27 09:33:13 +00005232 Object* object = NULL;
5233 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005234 String* result = String::cast(object);
5235 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005236 Object* element;
5237 { MaybeObject* maybe_element = codes->GetElement(i);
5238 if (!maybe_element->ToObject(&element)) return maybe_element;
5239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005240 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005241 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005242 }
5243 return result;
5244}
5245
5246
5247// kNotEscaped is generated by the following:
5248//
5249// #!/bin/perl
5250// for (my $i = 0; $i < 256; $i++) {
5251// print "\n" if $i % 16 == 0;
5252// my $c = chr($i);
5253// my $escaped = 1;
5254// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5255// print $escaped ? "0, " : "1, ";
5256// }
5257
5258
5259static bool IsNotEscaped(uint16_t character) {
5260 // Only for 8 bit characters, the rest are always escaped (in a different way)
5261 ASSERT(character < 256);
5262 static const char kNotEscaped[256] = {
5263 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5264 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5265 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5266 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5267 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5268 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5269 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5270 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5271 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5272 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5274 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5275 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5276 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5277 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5278 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5279 };
5280 return kNotEscaped[character] != 0;
5281}
5282
5283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005284RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005285 const char hex_chars[] = "0123456789ABCDEF";
5286 NoHandleAllocation ha;
5287 ASSERT(args.length() == 1);
5288 CONVERT_CHECKED(String, source, args[0]);
5289
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005290 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005291
5292 int escaped_length = 0;
5293 int length = source->length();
5294 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005295 Access<StringInputBuffer> buffer(
5296 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005297 buffer->Reset(source);
5298 while (buffer->has_more()) {
5299 uint16_t character = buffer->GetNext();
5300 if (character >= 256) {
5301 escaped_length += 6;
5302 } else if (IsNotEscaped(character)) {
5303 escaped_length++;
5304 } else {
5305 escaped_length += 3;
5306 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005307 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005308 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005309 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005310 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 return Failure::OutOfMemoryException();
5312 }
5313 }
5314 }
5315 // No length change implies no change. Return original string if no change.
5316 if (escaped_length == length) {
5317 return source;
5318 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005319 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005320 { MaybeObject* maybe_o =
5321 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005322 if (!maybe_o->ToObject(&o)) return maybe_o;
5323 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005324 String* destination = String::cast(o);
5325 int dest_position = 0;
5326
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005327 Access<StringInputBuffer> buffer(
5328 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005329 buffer->Rewind();
5330 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005331 uint16_t chr = buffer->GetNext();
5332 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005333 destination->Set(dest_position, '%');
5334 destination->Set(dest_position+1, 'u');
5335 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5336 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5337 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5338 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005339 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005340 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005341 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005342 dest_position++;
5343 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005344 destination->Set(dest_position, '%');
5345 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5346 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005347 dest_position += 3;
5348 }
5349 }
5350 return destination;
5351}
5352
5353
5354static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5355 static const signed char kHexValue['g'] = {
5356 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5357 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5358 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5359 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5360 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5361 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5362 -1, 10, 11, 12, 13, 14, 15 };
5363
5364 if (character1 > 'f') return -1;
5365 int hi = kHexValue[character1];
5366 if (hi == -1) return -1;
5367 if (character2 > 'f') return -1;
5368 int lo = kHexValue[character2];
5369 if (lo == -1) return -1;
5370 return (hi << 4) + lo;
5371}
5372
5373
ager@chromium.org870a0b62008-11-04 11:43:05 +00005374static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005375 int i,
5376 int length,
5377 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005378 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005379 int32_t hi = 0;
5380 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005381 if (character == '%' &&
5382 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005383 source->Get(i + 1) == 'u' &&
5384 (hi = TwoDigitHex(source->Get(i + 2),
5385 source->Get(i + 3))) != -1 &&
5386 (lo = TwoDigitHex(source->Get(i + 4),
5387 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005388 *step = 6;
5389 return (hi << 8) + lo;
5390 } else if (character == '%' &&
5391 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005392 (lo = TwoDigitHex(source->Get(i + 1),
5393 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005394 *step = 3;
5395 return lo;
5396 } else {
5397 *step = 1;
5398 return character;
5399 }
5400}
5401
5402
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005403RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005404 NoHandleAllocation ha;
5405 ASSERT(args.length() == 1);
5406 CONVERT_CHECKED(String, source, args[0]);
5407
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005408 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409
5410 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005411 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005412
5413 int unescaped_length = 0;
5414 for (int i = 0; i < length; unescaped_length++) {
5415 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005416 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005417 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005418 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005419 i += step;
5420 }
5421
5422 // No length change implies no change. Return original string if no change.
5423 if (unescaped_length == length)
5424 return source;
5425
lrn@chromium.org303ada72010-10-27 09:33:13 +00005426 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005427 { MaybeObject* maybe_o =
5428 ascii ?
5429 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5430 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005431 if (!maybe_o->ToObject(&o)) return maybe_o;
5432 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433 String* destination = String::cast(o);
5434
5435 int dest_position = 0;
5436 for (int i = 0; i < length; dest_position++) {
5437 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005438 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005439 i += step;
5440 }
5441 return destination;
5442}
5443
5444
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005445static const unsigned int kQuoteTableLength = 128u;
5446
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005447static const int kJsonQuotesCharactersPerEntry = 8;
5448static const char* const JsonQuotes =
5449 "\\u0000 \\u0001 \\u0002 \\u0003 "
5450 "\\u0004 \\u0005 \\u0006 \\u0007 "
5451 "\\b \\t \\n \\u000b "
5452 "\\f \\r \\u000e \\u000f "
5453 "\\u0010 \\u0011 \\u0012 \\u0013 "
5454 "\\u0014 \\u0015 \\u0016 \\u0017 "
5455 "\\u0018 \\u0019 \\u001a \\u001b "
5456 "\\u001c \\u001d \\u001e \\u001f "
5457 " ! \\\" # "
5458 "$ % & ' "
5459 "( ) * + "
5460 ", - . / "
5461 "0 1 2 3 "
5462 "4 5 6 7 "
5463 "8 9 : ; "
5464 "< = > ? "
5465 "@ A B C "
5466 "D E F G "
5467 "H I J K "
5468 "L M N O "
5469 "P Q R S "
5470 "T U V W "
5471 "X Y Z [ "
5472 "\\\\ ] ^ _ "
5473 "` a b c "
5474 "d e f g "
5475 "h i j k "
5476 "l m n o "
5477 "p q r s "
5478 "t u v w "
5479 "x y z { "
5480 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005481
5482
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005483// For a string that is less than 32k characters it should always be
5484// possible to allocate it in new space.
5485static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5486
5487
5488// Doing JSON quoting cannot make the string more than this many times larger.
5489static const int kJsonQuoteWorstCaseBlowup = 6;
5490
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005491static const int kSpaceForQuotesAndComma = 3;
5492static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005493
5494// Covers the entire ASCII range (all other characters are unchanged by JSON
5495// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005496static const byte JsonQuoteLengths[kQuoteTableLength] = {
5497 6, 6, 6, 6, 6, 6, 6, 6,
5498 2, 2, 2, 6, 2, 2, 6, 6,
5499 6, 6, 6, 6, 6, 6, 6, 6,
5500 6, 6, 6, 6, 6, 6, 6, 6,
5501 1, 1, 2, 1, 1, 1, 1, 1,
5502 1, 1, 1, 1, 1, 1, 1, 1,
5503 1, 1, 1, 1, 1, 1, 1, 1,
5504 1, 1, 1, 1, 1, 1, 1, 1,
5505 1, 1, 1, 1, 1, 1, 1, 1,
5506 1, 1, 1, 1, 1, 1, 1, 1,
5507 1, 1, 1, 1, 1, 1, 1, 1,
5508 1, 1, 1, 1, 2, 1, 1, 1,
5509 1, 1, 1, 1, 1, 1, 1, 1,
5510 1, 1, 1, 1, 1, 1, 1, 1,
5511 1, 1, 1, 1, 1, 1, 1, 1,
5512 1, 1, 1, 1, 1, 1, 1, 1,
5513};
5514
5515
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005516template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005517MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005518
5519
5520template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005521MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5522 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005523}
5524
5525
5526template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005527MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5528 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005529}
5530
5531
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005532template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005533static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5534 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005535 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005536 const Char* read_cursor = characters.start();
5537 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005538 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005539 int quoted_length = kSpaceForQuotes;
5540 while (read_cursor < end) {
5541 Char c = *(read_cursor++);
5542 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5543 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005544 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005545 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005546 }
5547 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005548 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5549 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005550 Object* new_object;
5551 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005552 return new_alloc;
5553 }
5554 StringType* new_string = StringType::cast(new_object);
5555
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005556 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005557 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005558 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005559 *(write_cursor++) = '"';
5560
5561 read_cursor = characters.start();
5562 while (read_cursor < end) {
5563 Char c = *(read_cursor++);
5564 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5565 *(write_cursor++) = c;
5566 } else {
5567 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5568 const char* replacement = JsonQuotes +
5569 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5570 for (int i = 0; i < len; i++) {
5571 *write_cursor++ = *replacement++;
5572 }
5573 }
5574 }
5575 *(write_cursor++) = '"';
5576 return new_string;
5577}
5578
5579
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005580template <typename SinkChar, typename SourceChar>
5581static inline SinkChar* WriteQuoteJsonString(
5582 Isolate* isolate,
5583 SinkChar* write_cursor,
5584 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005585 // SinkChar is only char if SourceChar is guaranteed to be char.
5586 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005587 const SourceChar* read_cursor = characters.start();
5588 const SourceChar* end = read_cursor + characters.length();
5589 *(write_cursor++) = '"';
5590 while (read_cursor < end) {
5591 SourceChar c = *(read_cursor++);
5592 if (sizeof(SourceChar) > 1u &&
5593 static_cast<unsigned>(c) >= kQuoteTableLength) {
5594 *(write_cursor++) = static_cast<SinkChar>(c);
5595 } else {
5596 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5597 const char* replacement = JsonQuotes +
5598 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5599 write_cursor[0] = replacement[0];
5600 if (len > 1) {
5601 write_cursor[1] = replacement[1];
5602 if (len > 2) {
5603 ASSERT(len == 6);
5604 write_cursor[2] = replacement[2];
5605 write_cursor[3] = replacement[3];
5606 write_cursor[4] = replacement[4];
5607 write_cursor[5] = replacement[5];
5608 }
5609 }
5610 write_cursor += len;
5611 }
5612 }
5613 *(write_cursor++) = '"';
5614 return write_cursor;
5615}
5616
5617
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005618template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005619static MaybeObject* QuoteJsonString(Isolate* isolate,
5620 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005621 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005622 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005623 int worst_case_length =
5624 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005625 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005626 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005627 }
5628
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005629 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5630 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005631 Object* new_object;
5632 if (!new_alloc->ToObject(&new_object)) {
5633 return new_alloc;
5634 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005635 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005636 // Even if our string is small enough to fit in new space we still have to
5637 // handle it being allocated in old space as may happen in the third
5638 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5639 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005640 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005641 }
5642 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005643 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005644
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005645 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005646 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005647 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005648 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5649 write_cursor,
5650 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005651 int final_length = static_cast<int>(
5652 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005653 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005654 isolate->heap()->new_space()->
5655 template ShrinkStringAtAllocationBoundary<StringType>(
5656 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005657 return new_string;
5658}
5659
5660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005661RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005662 NoHandleAllocation ha;
5663 CONVERT_CHECKED(String, str, args[0]);
5664 if (!str->IsFlat()) {
5665 MaybeObject* try_flatten = str->TryFlatten();
5666 Object* flat;
5667 if (!try_flatten->ToObject(&flat)) {
5668 return try_flatten;
5669 }
5670 str = String::cast(flat);
5671 ASSERT(str->IsFlat());
5672 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005673 String::FlatContent flat = str->GetFlatContent();
5674 ASSERT(flat.IsFlat());
5675 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005676 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005677 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005678 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005679 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005680 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005681 }
5682}
5683
5684
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005685RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005686 NoHandleAllocation ha;
5687 CONVERT_CHECKED(String, str, args[0]);
5688 if (!str->IsFlat()) {
5689 MaybeObject* try_flatten = str->TryFlatten();
5690 Object* flat;
5691 if (!try_flatten->ToObject(&flat)) {
5692 return try_flatten;
5693 }
5694 str = String::cast(flat);
5695 ASSERT(str->IsFlat());
5696 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005697 String::FlatContent flat = str->GetFlatContent();
5698 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005699 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005700 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005701 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005702 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005703 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005704 }
5705}
5706
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005707
5708template <typename Char, typename StringType>
5709static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5710 FixedArray* array,
5711 int worst_case_length) {
5712 int length = array->length();
5713
5714 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5715 worst_case_length);
5716 Object* new_object;
5717 if (!new_alloc->ToObject(&new_object)) {
5718 return new_alloc;
5719 }
5720 if (!isolate->heap()->new_space()->Contains(new_object)) {
5721 // Even if our string is small enough to fit in new space we still have to
5722 // handle it being allocated in old space as may happen in the third
5723 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5724 // CEntryStub::GenerateCore.
5725 return isolate->heap()->undefined_value();
5726 }
5727 AssertNoAllocation no_gc;
5728 StringType* new_string = StringType::cast(new_object);
5729 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5730
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005731 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005732 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005733 *(write_cursor++) = '[';
5734 for (int i = 0; i < length; i++) {
5735 if (i != 0) *(write_cursor++) = ',';
5736 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005737 String::FlatContent content = str->GetFlatContent();
5738 ASSERT(content.IsFlat());
5739 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005740 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5741 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005742 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005743 } else {
5744 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5745 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005746 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005747 }
5748 }
5749 *(write_cursor++) = ']';
5750
5751 int final_length = static_cast<int>(
5752 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005753 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005754 isolate->heap()->new_space()->
5755 template ShrinkStringAtAllocationBoundary<StringType>(
5756 new_string, final_length);
5757 return new_string;
5758}
5759
5760
5761RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5762 NoHandleAllocation ha;
5763 ASSERT(args.length() == 1);
5764 CONVERT_CHECKED(JSArray, array, args[0]);
5765
5766 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5767 FixedArray* elements = FixedArray::cast(array->elements());
5768 int n = elements->length();
5769 bool ascii = true;
5770 int total_length = 0;
5771
5772 for (int i = 0; i < n; i++) {
5773 Object* elt = elements->get(i);
5774 if (!elt->IsString()) return isolate->heap()->undefined_value();
5775 String* element = String::cast(elt);
5776 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5777 total_length += element->length();
5778 if (ascii && element->IsTwoByteRepresentation()) {
5779 ascii = false;
5780 }
5781 }
5782
5783 int worst_case_length =
5784 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5785 + total_length * kJsonQuoteWorstCaseBlowup;
5786
5787 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5788 return isolate->heap()->undefined_value();
5789 }
5790
5791 if (ascii) {
5792 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5793 elements,
5794 worst_case_length);
5795 } else {
5796 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5797 elements,
5798 worst_case_length);
5799 }
5800}
5801
5802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005803RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005804 NoHandleAllocation ha;
5805
5806 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005807 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005808
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005809 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005810
lrn@chromium.org25156de2010-04-06 13:10:27 +00005811 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005812 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005813 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005814}
5815
5816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005817RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005818 NoHandleAllocation ha;
5819 CONVERT_CHECKED(String, str, args[0]);
5820
5821 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005822 double value = StringToDouble(isolate->unicode_cache(),
5823 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005824
5825 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005826 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005827}
5828
5829
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005830template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005831MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005832 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005833 String* s,
5834 int length,
5835 int input_string_length,
5836 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005837 // We try this twice, once with the assumption that the result is no longer
5838 // than the input and, if that assumption breaks, again with the exact
5839 // length. This may not be pretty, but it is nicer than what was here before
5840 // and I hereby claim my vaffel-is.
5841 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005842 // Allocate the resulting string.
5843 //
5844 // NOTE: This assumes that the upper/lower case of an ascii
5845 // character is also ascii. This is currently the case, but it
5846 // might break in the future if we implement more context and locale
5847 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005848 Object* o;
5849 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005850 ? isolate->heap()->AllocateRawAsciiString(length)
5851 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005852 if (!maybe_o->ToObject(&o)) return maybe_o;
5853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005854 String* result = String::cast(o);
5855 bool has_changed_character = false;
5856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005857 // Convert all characters to upper case, assuming that they will fit
5858 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005859 Access<StringInputBuffer> buffer(
5860 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005861 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005862 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005863 // We can assume that the string is not empty
5864 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005865 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005866 bool has_next = buffer->has_more();
5867 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005868 int char_length = mapping->get(current, next, chars);
5869 if (char_length == 0) {
5870 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005871 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005872 i++;
5873 } else if (char_length == 1) {
5874 // Common case: converting the letter resulted in one character.
5875 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005876 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005877 has_changed_character = true;
5878 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005879 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005880 // We've assumed that the result would be as long as the
5881 // input but here is a character that converts to several
5882 // characters. No matter, we calculate the exact length
5883 // of the result and try the whole thing again.
5884 //
5885 // Note that this leaves room for optimization. We could just
5886 // memcpy what we already have to the result string. Also,
5887 // the result string is the last object allocated we could
5888 // "realloc" it and probably, in the vast majority of cases,
5889 // extend the existing string to be able to hold the full
5890 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005891 int next_length = 0;
5892 if (has_next) {
5893 next_length = mapping->get(next, 0, chars);
5894 if (next_length == 0) next_length = 1;
5895 }
5896 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005897 while (buffer->has_more()) {
5898 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005899 // NOTE: we use 0 as the next character here because, while
5900 // the next character may affect what a character converts to,
5901 // it does not in any case affect the length of what it convert
5902 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903 int char_length = mapping->get(current, 0, chars);
5904 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005905 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005906 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005907 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005908 return Failure::OutOfMemoryException();
5909 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005910 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005911 // Try again with the real length.
5912 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005913 } else {
5914 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005915 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005916 i++;
5917 }
5918 has_changed_character = true;
5919 }
5920 current = next;
5921 }
5922 if (has_changed_character) {
5923 return result;
5924 } else {
5925 // If we didn't actually change anything in doing the conversion
5926 // we simple return the result and let the converted string
5927 // become garbage; there is no reason to keep two identical strings
5928 // alive.
5929 return s;
5930 }
5931}
5932
5933
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005934namespace {
5935
lrn@chromium.org303ada72010-10-27 09:33:13 +00005936static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5937
5938
5939// Given a word and two range boundaries returns a word with high bit
5940// set in every byte iff the corresponding input byte was strictly in
5941// the range (m, n). All the other bits in the result are cleared.
5942// This function is only useful when it can be inlined and the
5943// boundaries are statically known.
5944// Requires: all bytes in the input word and the boundaries must be
5945// ascii (less than 0x7F).
5946static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5947 // Every byte in an ascii string is less than or equal to 0x7F.
5948 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5949 // Use strict inequalities since in edge cases the function could be
5950 // further simplified.
5951 ASSERT(0 < m && m < n && n < 0x7F);
5952 // Has high bit set in every w byte less than n.
5953 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5954 // Has high bit set in every w byte greater than m.
5955 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5956 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5957}
5958
5959
5960enum AsciiCaseConversion {
5961 ASCII_TO_LOWER,
5962 ASCII_TO_UPPER
5963};
5964
5965
5966template <AsciiCaseConversion dir>
5967struct FastAsciiConverter {
5968 static bool Convert(char* dst, char* src, int length) {
5969#ifdef DEBUG
5970 char* saved_dst = dst;
5971 char* saved_src = src;
5972#endif
5973 // We rely on the distance between upper and lower case letters
5974 // being a known power of 2.
5975 ASSERT('a' - 'A' == (1 << 5));
5976 // Boundaries for the range of input characters than require conversion.
5977 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5978 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5979 bool changed = false;
5980 char* const limit = src + length;
5981#ifdef V8_HOST_CAN_READ_UNALIGNED
5982 // Process the prefix of the input that requires no conversion one
5983 // (machine) word at a time.
5984 while (src <= limit - sizeof(uintptr_t)) {
5985 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5986 if (AsciiRangeMask(w, lo, hi) != 0) {
5987 changed = true;
5988 break;
5989 }
5990 *reinterpret_cast<uintptr_t*>(dst) = w;
5991 src += sizeof(uintptr_t);
5992 dst += sizeof(uintptr_t);
5993 }
5994 // Process the remainder of the input performing conversion when
5995 // required one word at a time.
5996 while (src <= limit - sizeof(uintptr_t)) {
5997 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5998 uintptr_t m = AsciiRangeMask(w, lo, hi);
5999 // The mask has high (7th) bit set in every byte that needs
6000 // conversion and we know that the distance between cases is
6001 // 1 << 5.
6002 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6003 src += sizeof(uintptr_t);
6004 dst += sizeof(uintptr_t);
6005 }
6006#endif
6007 // Process the last few bytes of the input (or the whole input if
6008 // unaligned access is not supported).
6009 while (src < limit) {
6010 char c = *src;
6011 if (lo < c && c < hi) {
6012 c ^= (1 << 5);
6013 changed = true;
6014 }
6015 *dst = c;
6016 ++src;
6017 ++dst;
6018 }
6019#ifdef DEBUG
6020 CheckConvert(saved_dst, saved_src, length, changed);
6021#endif
6022 return changed;
6023 }
6024
6025#ifdef DEBUG
6026 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6027 bool expected_changed = false;
6028 for (int i = 0; i < length; i++) {
6029 if (dst[i] == src[i]) continue;
6030 expected_changed = true;
6031 if (dir == ASCII_TO_LOWER) {
6032 ASSERT('A' <= src[i] && src[i] <= 'Z');
6033 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6034 } else {
6035 ASSERT(dir == ASCII_TO_UPPER);
6036 ASSERT('a' <= src[i] && src[i] <= 'z');
6037 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6038 }
6039 }
6040 ASSERT(expected_changed == changed);
6041 }
6042#endif
6043};
6044
6045
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006046struct ToLowerTraits {
6047 typedef unibrow::ToLowercase UnibrowConverter;
6048
lrn@chromium.org303ada72010-10-27 09:33:13 +00006049 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006050};
6051
6052
6053struct ToUpperTraits {
6054 typedef unibrow::ToUppercase UnibrowConverter;
6055
lrn@chromium.org303ada72010-10-27 09:33:13 +00006056 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006057};
6058
6059} // namespace
6060
6061
6062template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006063MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006064 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006065 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006066 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006067 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006068 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006069 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006070
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006071 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006072 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006073 if (length == 0) return s;
6074
6075 // Simpler handling of ascii strings.
6076 //
6077 // NOTE: This assumes that the upper/lower case of an ascii
6078 // character is also ascii. This is currently the case, but it
6079 // might break in the future if we implement more context and locale
6080 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006081 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006082 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006083 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006084 if (!maybe_o->ToObject(&o)) return maybe_o;
6085 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006086 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006087 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006088 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006089 return has_changed_character ? result : s;
6090 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006091
lrn@chromium.org303ada72010-10-27 09:33:13 +00006092 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006093 { MaybeObject* maybe_answer =
6094 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006095 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6096 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006097 if (answer->IsSmi()) {
6098 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006099 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006100 ConvertCaseHelper(isolate,
6101 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006102 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6103 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006104 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006105 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006106}
6107
6108
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006109RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006110 return ConvertCase<ToLowerTraits>(
6111 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006112}
6113
6114
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006115RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006116 return ConvertCase<ToUpperTraits>(
6117 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006118}
6119
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006120
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006121static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006122 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006123}
6124
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006126RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006127 NoHandleAllocation ha;
6128 ASSERT(args.length() == 3);
6129
6130 CONVERT_CHECKED(String, s, args[0]);
6131 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6132 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6133
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006134 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006135 int length = s->length();
6136
6137 int left = 0;
6138 if (trimLeft) {
6139 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6140 left++;
6141 }
6142 }
6143
6144 int right = length;
6145 if (trimRight) {
6146 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6147 right--;
6148 }
6149 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006150 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006151}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006152
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006153
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006154RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006155 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006156 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006157 CONVERT_ARG_CHECKED(String, subject, 0);
6158 CONVERT_ARG_CHECKED(String, pattern, 1);
6159 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6160
6161 int subject_length = subject->length();
6162 int pattern_length = pattern->length();
6163 RUNTIME_ASSERT(pattern_length > 0);
6164
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006165 if (limit == 0xffffffffu) {
6166 Handle<Object> cached_answer(StringSplitCache::Lookup(
6167 isolate->heap()->string_split_cache(),
6168 *subject,
6169 *pattern));
6170 if (*cached_answer != Smi::FromInt(0)) {
6171 Handle<JSArray> result =
6172 isolate->factory()->NewJSArrayWithElements(
6173 Handle<FixedArray>::cast(cached_answer));
6174 return *result;
6175 }
6176 }
6177
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006178 // The limit can be very large (0xffffffffu), but since the pattern
6179 // isn't empty, we can never create more parts than ~half the length
6180 // of the subject.
6181
6182 if (!subject->IsFlat()) FlattenString(subject);
6183
6184 static const int kMaxInitialListCapacity = 16;
6185
danno@chromium.org40cb8782011-05-25 07:58:50 +00006186 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006187
6188 // Find (up to limit) indices of separator and end-of-string in subject
6189 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6190 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006191 if (!pattern->IsFlat()) FlattenString(pattern);
6192
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006193 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006194
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006195 if (static_cast<uint32_t>(indices.length()) < limit) {
6196 indices.Add(subject_length);
6197 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006198
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006199 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006200
6201 // Create JSArray of substrings separated by separator.
6202 int part_count = indices.length();
6203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006204 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006205 MaybeObject* maybe_result = result->EnsureCanContainNonSmiElements();
6206 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006207 result->set_length(Smi::FromInt(part_count));
6208
6209 ASSERT(result->HasFastElements());
6210
6211 if (part_count == 1 && indices.at(0) == subject_length) {
6212 FixedArray::cast(result->elements())->set(0, *subject);
6213 return *result;
6214 }
6215
6216 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6217 int part_start = 0;
6218 for (int i = 0; i < part_count; i++) {
6219 HandleScope local_loop_handle;
6220 int part_end = indices.at(i);
6221 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006222 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006223 elements->set(i, *substring);
6224 part_start = part_end + pattern_length;
6225 }
6226
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006227 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006228 if (result->HasFastElements()) {
6229 StringSplitCache::Enter(isolate->heap(),
6230 isolate->heap()->string_split_cache(),
6231 *subject,
6232 *pattern,
6233 *elements);
6234 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006235 }
6236
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006237 return *result;
6238}
6239
6240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006241// Copies ascii characters to the given fixed array looking up
6242// one-char strings in the cache. Gives up on the first char that is
6243// not in the cache and fills the remainder with smi zeros. Returns
6244// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006245static int CopyCachedAsciiCharsToArray(Heap* heap,
6246 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006247 FixedArray* elements,
6248 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006249 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 FixedArray* ascii_cache = heap->single_character_string_cache();
6251 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006252 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006253 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006254 for (i = 0; i < length; ++i) {
6255 Object* value = ascii_cache->get(chars[i]);
6256 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006257 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006258 }
6259 if (i < length) {
6260 ASSERT(Smi::FromInt(0) == 0);
6261 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6262 }
6263#ifdef DEBUG
6264 for (int j = 0; j < length; ++j) {
6265 Object* element = elements->get(j);
6266 ASSERT(element == Smi::FromInt(0) ||
6267 (element->IsString() && String::cast(element)->LooksValid()));
6268 }
6269#endif
6270 return i;
6271}
6272
6273
6274// Converts a String to JSArray.
6275// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006276RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006277 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006278 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006279 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006280 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006281
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006282 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006283 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006284
6285 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006286 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006287 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006288 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006289 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006290 { MaybeObject* maybe_obj =
6291 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006292 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6293 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006294 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006295 String::FlatContent content = s->GetFlatContent();
6296 if (content.IsAscii()) {
6297 Vector<const char> chars = content.ToAsciiVector();
6298 // Note, this will initialize all elements (not only the prefix)
6299 // to prevent GC from seeing partially initialized array.
6300 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6301 chars.start(),
6302 *elements,
6303 length);
6304 } else {
6305 MemsetPointer(elements->data_start(),
6306 isolate->heap()->undefined_value(),
6307 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006308 }
6309 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006310 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006311 }
6312 for (int i = position; i < length; ++i) {
6313 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6314 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006315 }
6316
6317#ifdef DEBUG
6318 for (int i = 0; i < length; ++i) {
6319 ASSERT(String::cast(elements->get(i))->length() == 1);
6320 }
6321#endif
6322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006323 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006324}
6325
6326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006327RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006328 NoHandleAllocation ha;
6329 ASSERT(args.length() == 1);
6330 CONVERT_CHECKED(String, value, args[0]);
6331 return value->ToObject();
6332}
6333
6334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006336 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006337 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006338 return char_length == 0;
6339}
6340
6341
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006342RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006343 NoHandleAllocation ha;
6344 ASSERT(args.length() == 1);
6345
6346 Object* number = args[0];
6347 RUNTIME_ASSERT(number->IsNumber());
6348
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006349 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350}
6351
6352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006353RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006354 NoHandleAllocation ha;
6355 ASSERT(args.length() == 1);
6356
6357 Object* number = args[0];
6358 RUNTIME_ASSERT(number->IsNumber());
6359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006360 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006361}
6362
6363
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006364RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006365 NoHandleAllocation ha;
6366 ASSERT(args.length() == 1);
6367
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006368 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006369
6370 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6371 if (number > 0 && number <= Smi::kMaxValue) {
6372 return Smi::FromInt(static_cast<int>(number));
6373 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006374 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006375}
6376
6377
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006378RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006379 NoHandleAllocation ha;
6380 ASSERT(args.length() == 1);
6381
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006382 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006383
6384 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6385 if (number > 0 && number <= Smi::kMaxValue) {
6386 return Smi::FromInt(static_cast<int>(number));
6387 }
6388
6389 double double_value = DoubleToInteger(number);
6390 // Map both -0 and +0 to +0.
6391 if (double_value == 0) double_value = 0;
6392
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006393 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006394}
6395
6396
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006397RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006398 NoHandleAllocation ha;
6399 ASSERT(args.length() == 1);
6400
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006401 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006402 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403}
6404
6405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006406RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006407 NoHandleAllocation ha;
6408 ASSERT(args.length() == 1);
6409
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006410 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006411
6412 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6413 if (number > 0 && number <= Smi::kMaxValue) {
6414 return Smi::FromInt(static_cast<int>(number));
6415 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006416 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006417}
6418
6419
ager@chromium.org870a0b62008-11-04 11:43:05 +00006420// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6421// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006422RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006423 NoHandleAllocation ha;
6424 ASSERT(args.length() == 1);
6425
6426 Object* obj = args[0];
6427 if (obj->IsSmi()) {
6428 return obj;
6429 }
6430 if (obj->IsHeapNumber()) {
6431 double value = HeapNumber::cast(obj)->value();
6432 int int_value = FastD2I(value);
6433 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6434 return Smi::FromInt(int_value);
6435 }
6436 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006437 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006438}
6439
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006440
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006441RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006442 NoHandleAllocation ha;
6443 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006444 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006445}
6446
6447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006448RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006449 NoHandleAllocation ha;
6450 ASSERT(args.length() == 2);
6451
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006452 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6453 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006454 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006455}
6456
6457
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006458RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006459 NoHandleAllocation ha;
6460 ASSERT(args.length() == 2);
6461
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006462 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6463 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006464 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006465}
6466
6467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006468RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006469 NoHandleAllocation ha;
6470 ASSERT(args.length() == 2);
6471
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006472 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6473 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006474 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006475}
6476
6477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006478RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006479 NoHandleAllocation ha;
6480 ASSERT(args.length() == 1);
6481
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006482 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006483 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006484}
6485
6486
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006487RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006488 NoHandleAllocation ha;
6489 ASSERT(args.length() == 0);
6490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006491 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006492}
6493
6494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006495RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006496 NoHandleAllocation ha;
6497 ASSERT(args.length() == 2);
6498
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006499 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6500 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502}
6503
6504
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006505RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006506 NoHandleAllocation ha;
6507 ASSERT(args.length() == 2);
6508
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006509 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6510 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006511
ager@chromium.org3811b432009-10-28 14:53:37 +00006512 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006513 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006518RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519 NoHandleAllocation ha;
6520 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006521 CONVERT_CHECKED(String, str1, args[0]);
6522 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006523 isolate->counters()->string_add_runtime()->Increment();
6524 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006525}
6526
6527
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006528template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006529static inline void StringBuilderConcatHelper(String* special,
6530 sinkchar* sink,
6531 FixedArray* fixed_array,
6532 int array_length) {
6533 int position = 0;
6534 for (int i = 0; i < array_length; i++) {
6535 Object* element = fixed_array->get(i);
6536 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006537 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006538 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006539 int pos;
6540 int len;
6541 if (encoded_slice > 0) {
6542 // Position and length encoded in one smi.
6543 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6544 len = StringBuilderSubstringLength::decode(encoded_slice);
6545 } else {
6546 // Position and length encoded in two smis.
6547 Object* obj = fixed_array->get(++i);
6548 ASSERT(obj->IsSmi());
6549 pos = Smi::cast(obj)->value();
6550 len = -encoded_slice;
6551 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006552 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006553 sink + position,
6554 pos,
6555 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006556 position += len;
6557 } else {
6558 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006559 int element_length = string->length();
6560 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006561 position += element_length;
6562 }
6563 }
6564}
6565
6566
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006567RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006569 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006571 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006572 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006573 return Failure::OutOfMemoryException();
6574 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006575 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006576 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006577
6578 // This assumption is used by the slice encoding in one or two smis.
6579 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6580
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006581 MaybeObject* maybe_result = array->EnsureCanContainNonSmiElements();
6582 if (maybe_result->IsFailure()) return maybe_result;
6583
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006584 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006585 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006586 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 }
6588 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006589 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006590 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006591 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006592
6593 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006594 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006595 } else if (array_length == 1) {
6596 Object* first = fixed_array->get(0);
6597 if (first->IsString()) return first;
6598 }
6599
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006600 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601 int position = 0;
6602 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006603 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604 Object* elt = fixed_array->get(i);
6605 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006606 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006607 int smi_value = Smi::cast(elt)->value();
6608 int pos;
6609 int len;
6610 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006611 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006612 pos = StringBuilderSubstringPosition::decode(smi_value);
6613 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006614 } else {
6615 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006616 len = -smi_value;
6617 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006618 i++;
6619 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006620 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006621 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006622 Object* next_smi = fixed_array->get(i);
6623 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006624 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006625 }
6626 pos = Smi::cast(next_smi)->value();
6627 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006628 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006629 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006631 ASSERT(pos >= 0);
6632 ASSERT(len >= 0);
6633 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006634 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006635 }
6636 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006637 } else if (elt->IsString()) {
6638 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006639 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006640 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006641 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006642 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006643 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006645 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006647 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006648 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006649 return Failure::OutOfMemoryException();
6650 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006651 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006652 }
6653
6654 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006656
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006657 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006658 { MaybeObject* maybe_object =
6659 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006660 if (!maybe_object->ToObject(&object)) return maybe_object;
6661 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006662 SeqAsciiString* answer = SeqAsciiString::cast(object);
6663 StringBuilderConcatHelper(special,
6664 answer->GetChars(),
6665 fixed_array,
6666 array_length);
6667 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006668 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006669 { MaybeObject* maybe_object =
6670 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006671 if (!maybe_object->ToObject(&object)) return maybe_object;
6672 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006673 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6674 StringBuilderConcatHelper(special,
6675 answer->GetChars(),
6676 fixed_array,
6677 array_length);
6678 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006679 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680}
6681
6682
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006683RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006684 NoHandleAllocation ha;
6685 ASSERT(args.length() == 3);
6686 CONVERT_CHECKED(JSArray, array, args[0]);
6687 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006689 return Failure::OutOfMemoryException();
6690 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006691 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006692 CONVERT_CHECKED(String, separator, args[2]);
6693
6694 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006695 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006696 }
6697 FixedArray* fixed_array = FixedArray::cast(array->elements());
6698 if (fixed_array->length() < array_length) {
6699 array_length = fixed_array->length();
6700 }
6701
6702 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006703 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006704 } else if (array_length == 1) {
6705 Object* first = fixed_array->get(0);
6706 if (first->IsString()) return first;
6707 }
6708
6709 int separator_length = separator->length();
6710 int max_nof_separators =
6711 (String::kMaxLength + separator_length - 1) / separator_length;
6712 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006713 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006714 return Failure::OutOfMemoryException();
6715 }
6716 int length = (array_length - 1) * separator_length;
6717 for (int i = 0; i < array_length; i++) {
6718 Object* element_obj = fixed_array->get(i);
6719 if (!element_obj->IsString()) {
6720 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006721 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006722 }
6723 String* element = String::cast(element_obj);
6724 int increment = element->length();
6725 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006726 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006727 return Failure::OutOfMemoryException();
6728 }
6729 length += increment;
6730 }
6731
6732 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006733 { MaybeObject* maybe_object =
6734 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006735 if (!maybe_object->ToObject(&object)) return maybe_object;
6736 }
6737 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6738
6739 uc16* sink = answer->GetChars();
6740#ifdef DEBUG
6741 uc16* end = sink + length;
6742#endif
6743
6744 String* first = String::cast(fixed_array->get(0));
6745 int first_length = first->length();
6746 String::WriteToFlat(first, sink, 0, first_length);
6747 sink += first_length;
6748
6749 for (int i = 1; i < array_length; i++) {
6750 ASSERT(sink + separator_length <= end);
6751 String::WriteToFlat(separator, sink, 0, separator_length);
6752 sink += separator_length;
6753
6754 String* element = String::cast(fixed_array->get(i));
6755 int element_length = element->length();
6756 ASSERT(sink + element_length <= end);
6757 String::WriteToFlat(element, sink, 0, element_length);
6758 sink += element_length;
6759 }
6760 ASSERT(sink == end);
6761
6762 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6763 return answer;
6764}
6765
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006766template <typename Char>
6767static void JoinSparseArrayWithSeparator(FixedArray* elements,
6768 int elements_length,
6769 uint32_t array_length,
6770 String* separator,
6771 Vector<Char> buffer) {
6772 int previous_separator_position = 0;
6773 int separator_length = separator->length();
6774 int cursor = 0;
6775 for (int i = 0; i < elements_length; i += 2) {
6776 int position = NumberToInt32(elements->get(i));
6777 String* string = String::cast(elements->get(i + 1));
6778 int string_length = string->length();
6779 if (string->length() > 0) {
6780 while (previous_separator_position < position) {
6781 String::WriteToFlat<Char>(separator, &buffer[cursor],
6782 0, separator_length);
6783 cursor += separator_length;
6784 previous_separator_position++;
6785 }
6786 String::WriteToFlat<Char>(string, &buffer[cursor],
6787 0, string_length);
6788 cursor += string->length();
6789 }
6790 }
6791 if (separator_length > 0) {
6792 // Array length must be representable as a signed 32-bit number,
6793 // otherwise the total string length would have been too large.
6794 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6795 int last_array_index = static_cast<int>(array_length - 1);
6796 while (previous_separator_position < last_array_index) {
6797 String::WriteToFlat<Char>(separator, &buffer[cursor],
6798 0, separator_length);
6799 cursor += separator_length;
6800 previous_separator_position++;
6801 }
6802 }
6803 ASSERT(cursor <= buffer.length());
6804}
6805
6806
6807RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6808 NoHandleAllocation ha;
6809 ASSERT(args.length() == 3);
6810 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006811 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6812 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006813 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6814 CONVERT_CHECKED(String, separator, args[2]);
6815 // elements_array is fast-mode JSarray of alternating positions
6816 // (increasing order) and strings.
6817 // array_length is length of original array (used to add separators);
6818 // separator is string to put between elements. Assumed to be non-empty.
6819
6820 // Find total length of join result.
6821 int string_length = 0;
6822 bool is_ascii = true;
6823 int max_string_length = SeqAsciiString::kMaxLength;
6824 bool overflow = false;
6825 CONVERT_NUMBER_CHECKED(int, elements_length,
6826 Int32, elements_array->length());
6827 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6828 FixedArray* elements = FixedArray::cast(elements_array->elements());
6829 for (int i = 0; i < elements_length; i += 2) {
6830 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6831 CONVERT_CHECKED(String, string, elements->get(i + 1));
6832 int length = string->length();
6833 if (is_ascii && !string->IsAsciiRepresentation()) {
6834 is_ascii = false;
6835 max_string_length = SeqTwoByteString::kMaxLength;
6836 }
6837 if (length > max_string_length ||
6838 max_string_length - length < string_length) {
6839 overflow = true;
6840 break;
6841 }
6842 string_length += length;
6843 }
6844 int separator_length = separator->length();
6845 if (!overflow && separator_length > 0) {
6846 if (array_length <= 0x7fffffffu) {
6847 int separator_count = static_cast<int>(array_length) - 1;
6848 int remaining_length = max_string_length - string_length;
6849 if ((remaining_length / separator_length) >= separator_count) {
6850 string_length += separator_length * (array_length - 1);
6851 } else {
6852 // Not room for the separators within the maximal string length.
6853 overflow = true;
6854 }
6855 } else {
6856 // Nonempty separator and at least 2^31-1 separators necessary
6857 // means that the string is too large to create.
6858 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6859 overflow = true;
6860 }
6861 }
6862 if (overflow) {
6863 // Throw OutOfMemory exception for creating too large a string.
6864 V8::FatalProcessOutOfMemory("Array join result too large.");
6865 }
6866
6867 if (is_ascii) {
6868 MaybeObject* result_allocation =
6869 isolate->heap()->AllocateRawAsciiString(string_length);
6870 if (result_allocation->IsFailure()) return result_allocation;
6871 SeqAsciiString* result_string =
6872 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6873 JoinSparseArrayWithSeparator<char>(elements,
6874 elements_length,
6875 array_length,
6876 separator,
6877 Vector<char>(result_string->GetChars(),
6878 string_length));
6879 return result_string;
6880 } else {
6881 MaybeObject* result_allocation =
6882 isolate->heap()->AllocateRawTwoByteString(string_length);
6883 if (result_allocation->IsFailure()) return result_allocation;
6884 SeqTwoByteString* result_string =
6885 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6886 JoinSparseArrayWithSeparator<uc16>(elements,
6887 elements_length,
6888 array_length,
6889 separator,
6890 Vector<uc16>(result_string->GetChars(),
6891 string_length));
6892 return result_string;
6893 }
6894}
6895
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006897RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006898 NoHandleAllocation ha;
6899 ASSERT(args.length() == 2);
6900
6901 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6902 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006903 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006904}
6905
6906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006907RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006908 NoHandleAllocation ha;
6909 ASSERT(args.length() == 2);
6910
6911 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6912 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006913 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914}
6915
6916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006917RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006918 NoHandleAllocation ha;
6919 ASSERT(args.length() == 2);
6920
6921 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6922 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006923 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006924}
6925
6926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006927RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006928 NoHandleAllocation ha;
6929 ASSERT(args.length() == 1);
6930
6931 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006932 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006933}
6934
6935
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006936RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006937 NoHandleAllocation ha;
6938 ASSERT(args.length() == 2);
6939
6940 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6941 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006942 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006943}
6944
6945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006946RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006947 NoHandleAllocation ha;
6948 ASSERT(args.length() == 2);
6949
6950 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6951 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006952 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006953}
6954
6955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006956RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006957 NoHandleAllocation ha;
6958 ASSERT(args.length() == 2);
6959
6960 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6961 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006962 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006963}
6964
6965
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006966RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006967 NoHandleAllocation ha;
6968 ASSERT(args.length() == 2);
6969
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006970 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6971 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006972 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6973 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6974 if (x == y) return Smi::FromInt(EQUAL);
6975 Object* result;
6976 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6977 result = Smi::FromInt(EQUAL);
6978 } else {
6979 result = Smi::FromInt(NOT_EQUAL);
6980 }
6981 return result;
6982}
6983
6984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006985RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986 NoHandleAllocation ha;
6987 ASSERT(args.length() == 2);
6988
6989 CONVERT_CHECKED(String, x, args[0]);
6990 CONVERT_CHECKED(String, y, args[1]);
6991
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006992 bool not_equal = !x->Equals(y);
6993 // This is slightly convoluted because the value that signifies
6994 // equality is 0 and inequality is 1 so we have to negate the result
6995 // from String::Equals.
6996 ASSERT(not_equal == 0 || not_equal == 1);
6997 STATIC_CHECK(EQUAL == 0);
6998 STATIC_CHECK(NOT_EQUAL == 1);
6999 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007000}
7001
7002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007003RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004 NoHandleAllocation ha;
7005 ASSERT(args.length() == 3);
7006
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007007 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7008 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007009 if (isnan(x) || isnan(y)) return args[2];
7010 if (x == y) return Smi::FromInt(EQUAL);
7011 if (isless(x, y)) return Smi::FromInt(LESS);
7012 return Smi::FromInt(GREATER);
7013}
7014
7015
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007016// Compare two Smis as if they were converted to strings and then
7017// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007018RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007019 NoHandleAllocation ha;
7020 ASSERT(args.length() == 2);
7021
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007022 // Extract the integer values from the Smis.
7023 CONVERT_CHECKED(Smi, x, args[0]);
7024 CONVERT_CHECKED(Smi, y, args[1]);
7025 int x_value = x->value();
7026 int y_value = y->value();
7027
7028 // If the integers are equal so are the string representations.
7029 if (x_value == y_value) return Smi::FromInt(EQUAL);
7030
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007031 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007032 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007033 if (x_value == 0 || y_value == 0)
7034 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007035
ager@chromium.org32912102009-01-16 10:38:43 +00007036 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007037 // smallest because the char code of '-' is less than the char code
7038 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007039
7040 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7041 // architectures using 32-bit Smis.
7042 uint32_t x_scaled = x_value;
7043 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007044 if (x_value < 0 || y_value < 0) {
7045 if (y_value >= 0) return Smi::FromInt(LESS);
7046 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007047 x_scaled = -x_value;
7048 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007049 }
7050
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007051 static const uint32_t kPowersOf10[] = {
7052 1, 10, 100, 1000, 10*1000, 100*1000,
7053 1000*1000, 10*1000*1000, 100*1000*1000,
7054 1000*1000*1000
7055 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007056
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007057 // If the integers have the same number of decimal digits they can be
7058 // compared directly as the numeric order is the same as the
7059 // lexicographic order. If one integer has fewer digits, it is scaled
7060 // by some power of 10 to have the same number of digits as the longer
7061 // integer. If the scaled integers are equal it means the shorter
7062 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007063
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007064 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7065 int x_log2 = IntegerLog2(x_scaled);
7066 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7067 x_log10 -= x_scaled < kPowersOf10[x_log10];
7068
7069 int y_log2 = IntegerLog2(y_scaled);
7070 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7071 y_log10 -= y_scaled < kPowersOf10[y_log10];
7072
7073 int tie = EQUAL;
7074
7075 if (x_log10 < y_log10) {
7076 // X has fewer digits. We would like to simply scale up X but that
7077 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7078 // be scaled up to 9_000_000_000. So we scale up by the next
7079 // smallest power and scale down Y to drop one digit. It is OK to
7080 // drop one digit from the longer integer since the final digit is
7081 // past the length of the shorter integer.
7082 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7083 y_scaled /= 10;
7084 tie = LESS;
7085 } else if (y_log10 < x_log10) {
7086 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7087 x_scaled /= 10;
7088 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007089 }
7090
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007091 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7092 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7093 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007094}
7095
7096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007097static Object* StringInputBufferCompare(RuntimeState* state,
7098 String* x,
7099 String* y) {
7100 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7101 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007102 bufx.Reset(x);
7103 bufy.Reset(y);
7104 while (bufx.has_more() && bufy.has_more()) {
7105 int d = bufx.GetNext() - bufy.GetNext();
7106 if (d < 0) return Smi::FromInt(LESS);
7107 else if (d > 0) return Smi::FromInt(GREATER);
7108 }
7109
7110 // x is (non-trivial) prefix of y:
7111 if (bufy.has_more()) return Smi::FromInt(LESS);
7112 // y is prefix of x:
7113 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7114}
7115
7116
7117static Object* FlatStringCompare(String* x, String* y) {
7118 ASSERT(x->IsFlat());
7119 ASSERT(y->IsFlat());
7120 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7121 int prefix_length = x->length();
7122 if (y->length() < prefix_length) {
7123 prefix_length = y->length();
7124 equal_prefix_result = Smi::FromInt(GREATER);
7125 } else if (y->length() > prefix_length) {
7126 equal_prefix_result = Smi::FromInt(LESS);
7127 }
7128 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007129 String::FlatContent x_content = x->GetFlatContent();
7130 String::FlatContent y_content = y->GetFlatContent();
7131 if (x_content.IsAscii()) {
7132 Vector<const char> x_chars = x_content.ToAsciiVector();
7133 if (y_content.IsAscii()) {
7134 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007135 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007136 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007137 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007138 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7139 }
7140 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007141 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7142 if (y_content.IsAscii()) {
7143 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007144 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7145 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007146 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007147 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7148 }
7149 }
7150 Object* result;
7151 if (r == 0) {
7152 result = equal_prefix_result;
7153 } else {
7154 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7155 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007156 ASSERT(result ==
7157 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007158 return result;
7159}
7160
7161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007162RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007163 NoHandleAllocation ha;
7164 ASSERT(args.length() == 2);
7165
7166 CONVERT_CHECKED(String, x, args[0]);
7167 CONVERT_CHECKED(String, y, args[1]);
7168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007169 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007171 // A few fast case tests before we flatten.
7172 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007173 if (y->length() == 0) {
7174 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007175 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007176 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007177 return Smi::FromInt(LESS);
7178 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007179
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007180 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007181 if (d < 0) return Smi::FromInt(LESS);
7182 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007183
lrn@chromium.org303ada72010-10-27 09:33:13 +00007184 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007185 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007186 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7187 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007188 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007189 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7190 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007191
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007192 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007193 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007194}
7195
7196
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007197RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007198 NoHandleAllocation ha;
7199 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007200 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007201
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007202 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007203 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007204}
7205
7206
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007207RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007208 NoHandleAllocation ha;
7209 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007210 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007211
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007212 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007213 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007214}
7215
7216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007217RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007218 NoHandleAllocation ha;
7219 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007220 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007221
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007222 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007223 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007224}
7225
7226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007227static const double kPiDividedBy4 = 0.78539816339744830962;
7228
7229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007230RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007231 NoHandleAllocation ha;
7232 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007233 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007234
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007235 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7236 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007237 double result;
7238 if (isinf(x) && isinf(y)) {
7239 // Make sure that the result in case of two infinite arguments
7240 // is a multiple of Pi / 4. The sign of the result is determined
7241 // by the first argument (x) and the sign of the second argument
7242 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007243 int multiplier = (x < 0) ? -1 : 1;
7244 if (y < 0) multiplier *= 3;
7245 result = multiplier * kPiDividedBy4;
7246 } else {
7247 result = atan2(x, y);
7248 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007249 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007250}
7251
7252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007253RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007254 NoHandleAllocation ha;
7255 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007256 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007257
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007258 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007259 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007260}
7261
7262
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007263RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007264 NoHandleAllocation ha;
7265 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007266 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007267
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007268 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007269 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007270}
7271
7272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007273RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007274 NoHandleAllocation ha;
7275 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007276 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007277
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007278 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007279 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007280}
7281
7282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007283RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007284 NoHandleAllocation ha;
7285 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007286 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007287
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007288 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007289 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007290}
7291
7292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007293RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294 NoHandleAllocation ha;
7295 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007296 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007297
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007298 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007299 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007300}
7301
7302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007303RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304 NoHandleAllocation ha;
7305 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007306 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007307
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007308 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007309
7310 // If the second argument is a smi, it is much faster to call the
7311 // custom powi() function than the generic pow().
7312 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007313 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007314 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007315 }
7316
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007317 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007318 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007319}
7320
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007321// Fast version of Math.pow if we know that y is not an integer and
7322// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007323RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007324 NoHandleAllocation ha;
7325 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007326 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7327 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007328 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007329 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007330 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007331 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007332 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007333 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007334 }
7335}
7336
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007337
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007338RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007339 NoHandleAllocation ha;
7340 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007341 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007342
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007343 if (!args[0]->IsHeapNumber()) {
7344 // Must be smi. Return the argument unchanged for all the other types
7345 // to make fuzz-natives test happy.
7346 return args[0];
7347 }
7348
7349 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7350
7351 double value = number->value();
7352 int exponent = number->get_exponent();
7353 int sign = number->get_sign();
7354
danno@chromium.org160a7b02011-04-18 15:51:38 +00007355 if (exponent < -1) {
7356 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7357 if (sign) return isolate->heap()->minus_zero_value();
7358 return Smi::FromInt(0);
7359 }
7360
7361 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7362 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7363 // agument holds for 32-bit smis).
7364 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007365 return Smi::FromInt(static_cast<int>(value + 0.5));
7366 }
7367
7368 // If the magnitude is big enough, there's no place for fraction part. If we
7369 // try to add 0.5 to this number, 1.0 will be added instead.
7370 if (exponent >= 52) {
7371 return number;
7372 }
7373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007374 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007375
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007376 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007377 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378}
7379
7380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007381RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007382 NoHandleAllocation ha;
7383 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007384 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007385
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007386 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007387 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007388}
7389
7390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007391RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007392 NoHandleAllocation ha;
7393 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007394 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007396 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007397 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007398}
7399
7400
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007401RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007402 NoHandleAllocation ha;
7403 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007404 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007405
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007406 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007407 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007408}
7409
7410
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007411static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007412 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7413 181, 212, 243, 273, 304, 334};
7414 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7415 182, 213, 244, 274, 305, 335};
7416
7417 year += month / 12;
7418 month %= 12;
7419 if (month < 0) {
7420 year--;
7421 month += 12;
7422 }
7423
7424 ASSERT(month >= 0);
7425 ASSERT(month < 12);
7426
7427 // year_delta is an arbitrary number such that:
7428 // a) year_delta = -1 (mod 400)
7429 // b) year + year_delta > 0 for years in the range defined by
7430 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7431 // Jan 1 1970. This is required so that we don't run into integer
7432 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007433 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007434 // operations.
7435 static const int year_delta = 399999;
7436 static const int base_day = 365 * (1970 + year_delta) +
7437 (1970 + year_delta) / 4 -
7438 (1970 + year_delta) / 100 +
7439 (1970 + year_delta) / 400;
7440
7441 int year1 = year + year_delta;
7442 int day_from_year = 365 * year1 +
7443 year1 / 4 -
7444 year1 / 100 +
7445 year1 / 400 -
7446 base_day;
7447
7448 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007449 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007450 }
7451
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007452 return day_from_year + day_from_month_leap[month] + day - 1;
7453}
7454
7455
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007456RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007457 NoHandleAllocation ha;
7458 ASSERT(args.length() == 3);
7459
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007460 CONVERT_SMI_ARG_CHECKED(year, 0);
7461 CONVERT_SMI_ARG_CHECKED(month, 1);
7462 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007463
7464 return Smi::FromInt(MakeDay(year, month, date));
7465}
7466
7467
7468static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7469static const int kDaysIn4Years = 4 * 365 + 1;
7470static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7471static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7472static const int kDays1970to2000 = 30 * 365 + 7;
7473static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7474 kDays1970to2000;
7475static const int kYearsOffset = 400000;
7476
7477static const char kDayInYear[] = {
7478 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7479 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7480 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7481 22, 23, 24, 25, 26, 27, 28,
7482 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7483 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7484 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7485 22, 23, 24, 25, 26, 27, 28, 29, 30,
7486 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7487 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7488 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7489 22, 23, 24, 25, 26, 27, 28, 29, 30,
7490 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7491 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7492 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7493 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7494 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7495 22, 23, 24, 25, 26, 27, 28, 29, 30,
7496 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7497 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7498 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7499 22, 23, 24, 25, 26, 27, 28, 29, 30,
7500 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7501 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7502
7503 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7504 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7505 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7506 22, 23, 24, 25, 26, 27, 28,
7507 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7508 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7509 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7510 22, 23, 24, 25, 26, 27, 28, 29, 30,
7511 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7512 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7513 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7514 22, 23, 24, 25, 26, 27, 28, 29, 30,
7515 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7516 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7517 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7518 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7519 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7520 22, 23, 24, 25, 26, 27, 28, 29, 30,
7521 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7522 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7523 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7524 22, 23, 24, 25, 26, 27, 28, 29, 30,
7525 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7526 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7527
7528 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7529 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7530 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7531 22, 23, 24, 25, 26, 27, 28, 29,
7532 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7533 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7534 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7535 22, 23, 24, 25, 26, 27, 28, 29, 30,
7536 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7537 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7538 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7539 22, 23, 24, 25, 26, 27, 28, 29, 30,
7540 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7541 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7542 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7543 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7544 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7545 22, 23, 24, 25, 26, 27, 28, 29, 30,
7546 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7547 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7548 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7549 22, 23, 24, 25, 26, 27, 28, 29, 30,
7550 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7551 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7552
7553 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7554 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7555 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7556 22, 23, 24, 25, 26, 27, 28,
7557 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7558 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7559 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7560 22, 23, 24, 25, 26, 27, 28, 29, 30,
7561 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7562 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7563 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7564 22, 23, 24, 25, 26, 27, 28, 29, 30,
7565 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7566 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7567 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7568 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7569 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7570 22, 23, 24, 25, 26, 27, 28, 29, 30,
7571 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7572 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7573 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7574 22, 23, 24, 25, 26, 27, 28, 29, 30,
7575 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7576 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7577
7578static const char kMonthInYear[] = {
7579 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7580 0, 0, 0, 0, 0, 0,
7581 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7582 1, 1, 1,
7583 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7584 2, 2, 2, 2, 2, 2,
7585 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7586 3, 3, 3, 3, 3,
7587 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7588 4, 4, 4, 4, 4, 4,
7589 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7590 5, 5, 5, 5, 5,
7591 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7592 6, 6, 6, 6, 6, 6,
7593 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7594 7, 7, 7, 7, 7, 7,
7595 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7596 8, 8, 8, 8, 8,
7597 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7598 9, 9, 9, 9, 9, 9,
7599 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7600 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7601 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7602 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7603
7604 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7605 0, 0, 0, 0, 0, 0,
7606 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7607 1, 1, 1,
7608 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7609 2, 2, 2, 2, 2, 2,
7610 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7611 3, 3, 3, 3, 3,
7612 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7613 4, 4, 4, 4, 4, 4,
7614 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7615 5, 5, 5, 5, 5,
7616 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7617 6, 6, 6, 6, 6, 6,
7618 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7619 7, 7, 7, 7, 7, 7,
7620 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7621 8, 8, 8, 8, 8,
7622 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7623 9, 9, 9, 9, 9, 9,
7624 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7625 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7626 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7627 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7628
7629 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7630 0, 0, 0, 0, 0, 0,
7631 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7632 1, 1, 1, 1,
7633 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7634 2, 2, 2, 2, 2, 2,
7635 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7636 3, 3, 3, 3, 3,
7637 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7638 4, 4, 4, 4, 4, 4,
7639 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7640 5, 5, 5, 5, 5,
7641 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7642 6, 6, 6, 6, 6, 6,
7643 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7644 7, 7, 7, 7, 7, 7,
7645 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7646 8, 8, 8, 8, 8,
7647 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7648 9, 9, 9, 9, 9, 9,
7649 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7650 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7651 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7652 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7653
7654 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7655 0, 0, 0, 0, 0, 0,
7656 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7657 1, 1, 1,
7658 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7659 2, 2, 2, 2, 2, 2,
7660 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7661 3, 3, 3, 3, 3,
7662 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7663 4, 4, 4, 4, 4, 4,
7664 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7665 5, 5, 5, 5, 5,
7666 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7667 6, 6, 6, 6, 6, 6,
7668 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7669 7, 7, 7, 7, 7, 7,
7670 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7671 8, 8, 8, 8, 8,
7672 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7673 9, 9, 9, 9, 9, 9,
7674 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7675 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7676 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7677 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7678
7679
7680// This function works for dates from 1970 to 2099.
7681static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007682 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007683#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007684 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007685#endif
7686
7687 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7688 date %= kDaysIn4Years;
7689
7690 month = kMonthInYear[date];
7691 day = kDayInYear[date];
7692
7693 ASSERT(MakeDay(year, month, day) == save_date);
7694}
7695
7696
7697static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007698 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007699#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007700 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007701#endif
7702
7703 date += kDaysOffset;
7704 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7705 date %= kDaysIn400Years;
7706
7707 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7708
7709 date--;
7710 int yd1 = date / kDaysIn100Years;
7711 date %= kDaysIn100Years;
7712 year += 100 * yd1;
7713
7714 date++;
7715 int yd2 = date / kDaysIn4Years;
7716 date %= kDaysIn4Years;
7717 year += 4 * yd2;
7718
7719 date--;
7720 int yd3 = date / 365;
7721 date %= 365;
7722 year += yd3;
7723
7724 bool is_leap = (!yd1 || yd2) && !yd3;
7725
7726 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007727 ASSERT(is_leap || (date >= 0));
7728 ASSERT((date < 365) || (is_leap && (date < 366)));
7729 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7730 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7731 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007732
7733 if (is_leap) {
7734 day = kDayInYear[2*365 + 1 + date];
7735 month = kMonthInYear[2*365 + 1 + date];
7736 } else {
7737 day = kDayInYear[date];
7738 month = kMonthInYear[date];
7739 }
7740
7741 ASSERT(MakeDay(year, month, day) == save_date);
7742}
7743
7744
7745static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007746 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007747 if (date >= 0 && date < 32 * kDaysIn4Years) {
7748 DateYMDFromTimeAfter1970(date, year, month, day);
7749 } else {
7750 DateYMDFromTimeSlow(date, year, month, day);
7751 }
7752}
7753
7754
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007755RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007756 NoHandleAllocation ha;
7757 ASSERT(args.length() == 2);
7758
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007759 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007760 CONVERT_CHECKED(JSArray, res_array, args[1]);
7761
7762 int year, month, day;
7763 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7764
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007765 RUNTIME_ASSERT(res_array->elements()->map() ==
7766 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007767 FixedArray* elms = FixedArray::cast(res_array->elements());
7768 RUNTIME_ASSERT(elms->length() == 3);
7769
7770 elms->set(0, Smi::FromInt(year));
7771 elms->set(1, Smi::FromInt(month));
7772 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007774 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007775}
7776
7777
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007778RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007779 HandleScope scope(isolate);
7780 ASSERT(args.length() == 3);
7781
7782 Handle<JSFunction> callee = args.at<JSFunction>(0);
7783 Object** parameters = reinterpret_cast<Object**>(args[1]);
7784 const int argument_count = Smi::cast(args[2])->value();
7785
7786 Handle<JSObject> result =
7787 isolate->factory()->NewArgumentsObject(callee, argument_count);
7788 // Allocate the elements if needed.
7789 int parameter_count = callee->shared()->formal_parameter_count();
7790 if (argument_count > 0) {
7791 if (parameter_count > 0) {
7792 int mapped_count = Min(argument_count, parameter_count);
7793 Handle<FixedArray> parameter_map =
7794 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7795 parameter_map->set_map(
7796 isolate->heap()->non_strict_arguments_elements_map());
7797
7798 Handle<Map> old_map(result->map());
7799 Handle<Map> new_map =
7800 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007801 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007802
7803 result->set_map(*new_map);
7804 result->set_elements(*parameter_map);
7805
7806 // Store the context and the arguments array at the beginning of the
7807 // parameter map.
7808 Handle<Context> context(isolate->context());
7809 Handle<FixedArray> arguments =
7810 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7811 parameter_map->set(0, *context);
7812 parameter_map->set(1, *arguments);
7813
7814 // Loop over the actual parameters backwards.
7815 int index = argument_count - 1;
7816 while (index >= mapped_count) {
7817 // These go directly in the arguments array and have no
7818 // corresponding slot in the parameter map.
7819 arguments->set(index, *(parameters - index - 1));
7820 --index;
7821 }
7822
7823 ScopeInfo<> scope_info(callee->shared()->scope_info());
7824 while (index >= 0) {
7825 // Detect duplicate names to the right in the parameter list.
7826 Handle<String> name = scope_info.parameter_name(index);
7827 int context_slot_count = scope_info.number_of_context_slots();
7828 bool duplicate = false;
7829 for (int j = index + 1; j < parameter_count; ++j) {
7830 if (scope_info.parameter_name(j).is_identical_to(name)) {
7831 duplicate = true;
7832 break;
7833 }
7834 }
7835
7836 if (duplicate) {
7837 // This goes directly in the arguments array with a hole in the
7838 // parameter map.
7839 arguments->set(index, *(parameters - index - 1));
7840 parameter_map->set_the_hole(index + 2);
7841 } else {
7842 // The context index goes in the parameter map with a hole in the
7843 // arguments array.
7844 int context_index = -1;
7845 for (int j = Context::MIN_CONTEXT_SLOTS;
7846 j < context_slot_count;
7847 ++j) {
7848 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7849 context_index = j;
7850 break;
7851 }
7852 }
7853 ASSERT(context_index >= 0);
7854 arguments->set_the_hole(index);
7855 parameter_map->set(index + 2, Smi::FromInt(context_index));
7856 }
7857
7858 --index;
7859 }
7860 } else {
7861 // If there is no aliasing, the arguments object elements are not
7862 // special in any way.
7863 Handle<FixedArray> elements =
7864 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7865 result->set_elements(*elements);
7866 for (int i = 0; i < argument_count; ++i) {
7867 elements->set(i, *(parameters - i - 1));
7868 }
7869 }
7870 }
7871 return *result;
7872}
7873
7874
7875RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007876 NoHandleAllocation ha;
7877 ASSERT(args.length() == 3);
7878
7879 JSFunction* callee = JSFunction::cast(args[0]);
7880 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007881 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007882
lrn@chromium.org303ada72010-10-27 09:33:13 +00007883 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007884 { MaybeObject* maybe_result =
7885 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007886 if (!maybe_result->ToObject(&result)) return maybe_result;
7887 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007888 // Allocate the elements if needed.
7889 if (length > 0) {
7890 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007891 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007892 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007893 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7894 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007895
7896 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007897 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007899 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007900
7901 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007902 for (int i = 0; i < length; i++) {
7903 array->set(i, *--parameters, mode);
7904 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007905 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007906 }
7907 return result;
7908}
7909
7910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007911RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007912 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007913 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007914 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007915 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007916 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007917
whesse@chromium.org7b260152011-06-20 15:33:18 +00007918 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007919 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007920 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007921 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007922 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7923 context,
7924 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007925 return *result;
7926}
7927
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007928
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007929static SmartArrayPointer<Handle<Object> > GetNonBoundArguments(
7930 int bound_argc,
7931 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007932 // Find frame containing arguments passed to the caller.
7933 JavaScriptFrameIterator it;
7934 JavaScriptFrame* frame = it.frame();
7935 List<JSFunction*> functions(2);
7936 frame->GetFunctions(&functions);
7937 if (functions.length() > 1) {
7938 int inlined_frame_index = functions.length() - 1;
7939 JSFunction* inlined_function = functions[inlined_frame_index];
7940 int args_count = inlined_function->shared()->formal_parameter_count();
7941 ScopedVector<SlotRef> args_slots(args_count);
7942 SlotRef::ComputeSlotMappingForArguments(frame,
7943 inlined_frame_index,
7944 &args_slots);
7945
7946 *total_argc = bound_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007947 SmartArrayPointer<Handle<Object> > param_data(
7948 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007949 for (int i = 0; i < args_count; i++) {
7950 Handle<Object> val = args_slots[i].GetValue();
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007951 param_data[bound_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007952 }
7953 return param_data;
7954 } else {
7955 it.AdvanceToArgumentsFrame();
7956 frame = it.frame();
7957 int args_count = frame->ComputeParametersCount();
7958
7959 *total_argc = bound_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007960 SmartArrayPointer<Handle<Object> > param_data(
7961 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007962 for (int i = 0; i < args_count; i++) {
7963 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007964 param_data[bound_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007965 }
7966 return param_data;
7967 }
7968}
7969
7970
7971RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007972 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007973 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007974 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007975 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007976
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007977 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007978 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007979 int bound_argc = 0;
7980 if (!args[1]->IsNull()) {
7981 CONVERT_ARG_CHECKED(JSArray, params, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00007982 RUNTIME_ASSERT(params->HasFastTypeElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007983 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007984 bound_argc = Smi::cast(params->length())->value();
7985 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007987 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007988 SmartArrayPointer<Handle<Object> > param_data =
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007989 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007990 for (int i = 0; i < bound_argc; i++) {
7991 Handle<Object> val = Handle<Object>(bound_args->get(i));
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00007992 param_data[i] = val;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007993 }
7994
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007995 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007996 Handle<Object> result =
7997 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007998 if (exception) {
7999 return Failure::Exception();
8000 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008001
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008002 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008003 return *result;
8004}
8005
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008006
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008007static void TrySettingInlineConstructStub(Isolate* isolate,
8008 Handle<JSFunction> function) {
8009 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008010 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008011 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008012 }
8013 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008014 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00008015 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008016 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008017 function->shared()->set_construct_stub(
8018 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008019 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008020 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008021}
8022
8023
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008024RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008025 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008026 ASSERT(args.length() == 1);
8027
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008028 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008029
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008030 // If the constructor isn't a proper function we throw a type error.
8031 if (!constructor->IsJSFunction()) {
8032 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8033 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008034 isolate->factory()->NewTypeError("not_constructor", arguments);
8035 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008036 }
8037
8038 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008039
8040 // If function should not have prototype, construction is not allowed. In this
8041 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008042 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008043 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8044 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008045 isolate->factory()->NewTypeError("not_constructor", arguments);
8046 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008047 }
8048
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008049#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008050 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008051 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008052 if (debug->StepInActive()) {
8053 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008054 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008055#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008056
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008057 if (function->has_initial_map()) {
8058 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008059 // The 'Function' function ignores the receiver object when
8060 // called using 'new' and creates a new JSFunction object that
8061 // is returned. The receiver object is only used for error
8062 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008063 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008064 // allocate JSFunctions since it does not properly initialize
8065 // the shared part of the function. Since the receiver is
8066 // ignored anyway, we use the global object as the receiver
8067 // instead of a new JSFunction object. This way, errors are
8068 // reported the same way whether or not 'Function' is called
8069 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008070 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008071 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008072 }
8073
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008074 // The function should be compiled for the optimization hints to be
8075 // available. We cannot use EnsureCompiled because that forces a
8076 // compilation through the shared function info which makes it
8077 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008078 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008079 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008080
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008081 if (!function->has_initial_map() &&
8082 shared->IsInobjectSlackTrackingInProgress()) {
8083 // The tracking is already in progress for another function. We can only
8084 // track one initial_map at a time, so we force the completion before the
8085 // function is called as a constructor for the first time.
8086 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008087 }
8088
8089 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008090 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8091 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008092 // Delay setting the stub if inobject slack tracking is in progress.
8093 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008094 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008095 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008097 isolate->counters()->constructed_objects()->Increment();
8098 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008099
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008100 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008101}
8102
8103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008104RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008105 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008106 ASSERT(args.length() == 1);
8107
8108 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8109 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008110 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008112 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008113}
8114
8115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008116RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008117 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008118 ASSERT(args.length() == 1);
8119
8120 Handle<JSFunction> function = args.at<JSFunction>(0);
8121#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008122 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008123 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008124 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008125 PrintF("]\n");
8126 }
8127#endif
8128
lrn@chromium.org34e60782011-09-15 07:25:40 +00008129 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008130 ASSERT(!function->is_compiled());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008131 if (!CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008132 return Failure::Exception();
8133 }
8134
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008135 // All done. Return the compiled code.
8136 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008137 return function->code();
8138}
8139
8140
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008141RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008142 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008143 ASSERT(args.length() == 1);
8144 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008145
8146 // If the function is not compiled ignore the lazy
8147 // recompilation. This can happen if the debugger is activated and
8148 // the function is returned to the not compiled state.
8149 if (!function->shared()->is_compiled()) {
8150 function->ReplaceCode(function->shared()->code());
8151 return function->code();
8152 }
8153
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008154 // If the function is not optimizable or debugger is active continue using the
8155 // code from the full compiler.
8156 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008157 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008158 if (FLAG_trace_opt) {
8159 PrintF("[failed to optimize ");
8160 function->PrintName();
8161 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8162 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008163 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008164 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008165 function->ReplaceCode(function->shared()->code());
8166 return function->code();
8167 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008168 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008169 return function->code();
8170 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008171 if (FLAG_trace_opt) {
8172 PrintF("[failed to optimize ");
8173 function->PrintName();
8174 PrintF(": optimized compilation failed]\n");
8175 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008176 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008177 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008178}
8179
8180
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008181class ActivationsFinder : public ThreadVisitor {
8182 public:
8183 explicit ActivationsFinder(JSFunction* function)
8184 : function_(function), has_activations_(false) {}
8185
8186 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8187 if (has_activations_) return;
8188
8189 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8190 JavaScriptFrame* frame = it.frame();
8191 if (frame->is_optimized() && frame->function() == function_) {
8192 has_activations_ = true;
8193 return;
8194 }
8195 }
8196 }
8197
8198 bool has_activations() { return has_activations_; }
8199
8200 private:
8201 JSFunction* function_;
8202 bool has_activations_;
8203};
8204
8205
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008206RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008208 ASSERT(args.length() == 1);
8209 RUNTIME_ASSERT(args[0]->IsSmi());
8210 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008211 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8213 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008214 int frames = deoptimizer->output_count();
8215
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008216 deoptimizer->MaterializeHeapNumbers();
8217 delete deoptimizer;
8218
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008219 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008220 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008221 for (int i = 0; i < frames - 1; i++) it.Advance();
8222 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008223
8224 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008225 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008226 Handle<Object> arguments;
8227 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008228 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008229 if (arguments.is_null()) {
8230 // FunctionGetArguments can't throw an exception, so cast away the
8231 // doubt with an assert.
8232 arguments = Handle<Object>(
8233 Accessors::FunctionGetArguments(*function,
8234 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008235 ASSERT(*arguments != isolate->heap()->null_value());
8236 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008237 }
8238 frame->SetExpression(i, *arguments);
8239 }
8240 }
8241
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008242 if (type == Deoptimizer::EAGER) {
8243 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008244 }
8245
8246 // Avoid doing too much work when running with --always-opt and keep
8247 // the optimized code around.
8248 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008250 }
8251
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008252 // Find other optimized activations of the function.
8253 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008254 while (!it.done()) {
8255 JavaScriptFrame* frame = it.frame();
8256 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008257 has_other_activations = true;
8258 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008259 }
8260 it.Advance();
8261 }
8262
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008263 if (!has_other_activations) {
8264 ActivationsFinder activations_finder(*function);
8265 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8266 has_other_activations = activations_finder.has_activations();
8267 }
8268
8269 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008270 if (FLAG_trace_deopt) {
8271 PrintF("[removing optimized code for: ");
8272 function->PrintName();
8273 PrintF("]\n");
8274 }
8275 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008276 } else {
8277 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008278 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008279 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008280}
8281
8282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008283RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008285 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008286 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008287}
8288
8289
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008290RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008291 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008292 ASSERT(args.length() == 1);
8293 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008294 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008295
8296 Deoptimizer::DeoptimizeFunction(*function);
8297
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008299}
8300
8301
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008302RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8303#if defined(USE_SIMULATOR)
8304 return isolate->heap()->true_value();
8305#else
8306 return isolate->heap()->false_value();
8307#endif
8308}
8309
8310
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008311RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8312 HandleScope scope(isolate);
8313 ASSERT(args.length() == 1);
8314 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8315 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8316 function->MarkForLazyRecompilation();
8317 return isolate->heap()->undefined_value();
8318}
8319
8320
lrn@chromium.org1c092762011-05-09 09:42:16 +00008321RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8322 HandleScope scope(isolate);
8323 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008324 // The least significant bit (after untagging) indicates whether the
8325 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008326 if (!V8::UseCrankshaft()) {
8327 return Smi::FromInt(4); // 4 == "never".
8328 }
8329 if (FLAG_always_opt) {
8330 return Smi::FromInt(3); // 3 == "always".
8331 }
8332 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8333 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8334 : Smi::FromInt(2); // 2 == "no".
8335}
8336
8337
8338RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8339 HandleScope scope(isolate);
8340 ASSERT(args.length() == 1);
8341 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8342 return Smi::FromInt(function->shared()->opt_count());
8343}
8344
8345
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008346RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008347 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008348 ASSERT(args.length() == 1);
8349 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8350
8351 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008352 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008353
8354 // We have hit a back edge in an unoptimized frame for a function that was
8355 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008356 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008357 // Keep track of whether we've succeeded in optimizing.
8358 bool succeeded = unoptimized->optimizable();
8359 if (succeeded) {
8360 // If we are trying to do OSR when there are already optimized
8361 // activations of the function, it means (a) the function is directly or
8362 // indirectly recursive and (b) an optimized invocation has been
8363 // deoptimized so that we are currently in an unoptimized activation.
8364 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008365 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008366 while (succeeded && !it.done()) {
8367 JavaScriptFrame* frame = it.frame();
8368 succeeded = !frame->is_optimized() || frame->function() != *function;
8369 it.Advance();
8370 }
8371 }
8372
8373 int ast_id = AstNode::kNoNumber;
8374 if (succeeded) {
8375 // The top JS function is this one, the PC is somewhere in the
8376 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008377 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008378 JavaScriptFrame* frame = it.frame();
8379 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008380 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008381 ASSERT(unoptimized->contains(frame->pc()));
8382
8383 // Use linear search of the unoptimized code's stack check table to find
8384 // the AST id matching the PC.
8385 Address start = unoptimized->instruction_start();
8386 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008387 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008388 uint32_t table_length = Memory::uint32_at(table_cursor);
8389 table_cursor += kIntSize;
8390 for (unsigned i = 0; i < table_length; ++i) {
8391 // Table entries are (AST id, pc offset) pairs.
8392 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8393 if (pc_offset == target_pc_offset) {
8394 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8395 break;
8396 }
8397 table_cursor += 2 * kIntSize;
8398 }
8399 ASSERT(ast_id != AstNode::kNoNumber);
8400 if (FLAG_trace_osr) {
8401 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8402 function->PrintName();
8403 PrintF("]\n");
8404 }
8405
8406 // Try to compile the optimized code. A true return value from
8407 // CompileOptimized means that compilation succeeded, not necessarily
8408 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008409 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8410 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008411 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8412 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008413 if (data->OsrPcOffset()->value() >= 0) {
8414 if (FLAG_trace_osr) {
8415 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008416 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008417 }
8418 ASSERT(data->OsrAstId()->value() == ast_id);
8419 } else {
8420 // We may never generate the desired OSR entry if we emit an
8421 // early deoptimize.
8422 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008423 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008424 } else {
8425 succeeded = false;
8426 }
8427 }
8428
8429 // Revert to the original stack checks in the original unoptimized code.
8430 if (FLAG_trace_osr) {
8431 PrintF("[restoring original stack checks in ");
8432 function->PrintName();
8433 PrintF("]\n");
8434 }
8435 StackCheckStub check_stub;
8436 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008437 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008438 Deoptimizer::RevertStackCheckCode(*unoptimized,
8439 *check_code,
8440 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008441
8442 // Allow OSR only at nesting level zero again.
8443 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8444
8445 // If the optimization attempt succeeded, return the AST id tagged as a
8446 // smi. This tells the builtin that we need to translate the unoptimized
8447 // frame to an optimized one.
8448 if (succeeded) {
8449 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8450 return Smi::FromInt(ast_id);
8451 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008452 if (function->IsMarkedForLazyRecompilation()) {
8453 function->ReplaceCode(function->shared()->code());
8454 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008455 return Smi::FromInt(-1);
8456 }
8457}
8458
8459
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008460RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8461 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8462 return isolate->heap()->undefined_value();
8463}
8464
8465
lrn@chromium.org34e60782011-09-15 07:25:40 +00008466RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8467 HandleScope scope(isolate);
8468 ASSERT(args.length() == 5);
8469 CONVERT_CHECKED(JSReceiver, fun, args[0]);
8470 Object* receiver = args[1];
8471 CONVERT_CHECKED(JSObject, arguments, args[2]);
8472 CONVERT_CHECKED(Smi, shift, args[3]);
8473 CONVERT_CHECKED(Smi, arity, args[4]);
8474
8475 int offset = shift->value();
8476 int argc = arity->value();
8477 ASSERT(offset >= 0);
8478 ASSERT(argc >= 0);
8479
8480 // If there are too many arguments, allocate argv via malloc.
8481 const int argv_small_size = 10;
8482 Handle<Object> argv_small_buffer[argv_small_size];
8483 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8484 Handle<Object>* argv = argv_small_buffer;
8485 if (argc > argv_small_size) {
8486 argv = new Handle<Object>[argc];
8487 if (argv == NULL) return isolate->StackOverflow();
8488 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8489 }
8490
8491 for (int i = 0; i < argc; ++i) {
8492 MaybeObject* maybe = arguments->GetElement(offset + i);
8493 Object* object;
8494 if (!maybe->To<Object>(&object)) return maybe;
8495 argv[i] = Handle<Object>(object);
8496 }
8497
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008498 bool threw;
lrn@chromium.org34e60782011-09-15 07:25:40 +00008499 Handle<JSReceiver> hfun(fun);
8500 Handle<Object> hreceiver(receiver);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008501 Handle<Object> result =
8502 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008503
8504 if (threw) return Failure::Exception();
8505 return *result;
8506}
8507
8508
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008509RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008510 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008511 ASSERT(args.length() == 1);
8512 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8513 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8514}
8515
8516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008517RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008518 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008519 ASSERT(args.length() == 1);
8520 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8521 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8522}
8523
8524
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008525RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008526 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008527 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008528
kasper.lund7276f142008-07-30 08:49:36 +00008529 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008530 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008531 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008532 { MaybeObject* maybe_result =
8533 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008534 if (!maybe_result->ToObject(&result)) return maybe_result;
8535 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008536
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008537 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008538
kasper.lund7276f142008-07-30 08:49:36 +00008539 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008540}
8541
lrn@chromium.org303ada72010-10-27 09:33:13 +00008542
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008543RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8544 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008545 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008546 JSObject* extension_object;
8547 if (args[0]->IsJSObject()) {
8548 extension_object = JSObject::cast(args[0]);
8549 } else {
8550 // Convert the object to a proper JavaScript object.
8551 MaybeObject* maybe_js_object = args[0]->ToObject();
8552 if (!maybe_js_object->To(&extension_object)) {
8553 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8554 HandleScope scope(isolate);
8555 Handle<Object> handle = args.at<Object>(0);
8556 Handle<Object> result =
8557 isolate->factory()->NewTypeError("with_expression",
8558 HandleVector(&handle, 1));
8559 return isolate->Throw(*result);
8560 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008561 return maybe_js_object;
8562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008563 }
8564 }
8565
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008566 JSFunction* function;
8567 if (args[1]->IsSmi()) {
8568 // A smi sentinel indicates a context nested inside global code rather
8569 // than some function. There is a canonical empty function that can be
8570 // gotten from the global context.
8571 function = isolate->context()->global_context()->closure();
8572 } else {
8573 function = JSFunction::cast(args[1]);
8574 }
8575
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008576 Context* context;
8577 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008578 isolate->heap()->AllocateWithContext(function,
8579 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008580 extension_object);
8581 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008582 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008583 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008584}
8585
8586
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008587RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008588 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008589 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008590 String* name = String::cast(args[0]);
8591 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008592 JSFunction* function;
8593 if (args[2]->IsSmi()) {
8594 // A smi sentinel indicates a context nested inside global code rather
8595 // than some function. There is a canonical empty function that can be
8596 // gotten from the global context.
8597 function = isolate->context()->global_context()->closure();
8598 } else {
8599 function = JSFunction::cast(args[2]);
8600 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008601 Context* context;
8602 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008603 isolate->heap()->AllocateCatchContext(function,
8604 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008605 name,
8606 thrown_object);
8607 if (!maybe_context->To(&context)) return maybe_context;
8608 isolate->set_context(context);
8609 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008610}
8611
8612
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008613RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8614 NoHandleAllocation ha;
8615 ASSERT(args.length() == 2);
8616 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8617 JSFunction* function;
8618 if (args[1]->IsSmi()) {
8619 // A smi sentinel indicates a context nested inside global code rather
8620 // than some function. There is a canonical empty function that can be
8621 // gotten from the global context.
8622 function = isolate->context()->global_context()->closure();
8623 } else {
8624 function = JSFunction::cast(args[1]);
8625 }
8626 Context* context;
8627 MaybeObject* maybe_context =
8628 isolate->heap()->AllocateBlockContext(function,
8629 isolate->context(),
8630 scope_info);
8631 if (!maybe_context->To(&context)) return maybe_context;
8632 isolate->set_context(context);
8633 return context;
8634}
8635
8636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008637RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008638 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008639 ASSERT(args.length() == 2);
8640
8641 CONVERT_ARG_CHECKED(Context, context, 0);
8642 CONVERT_ARG_CHECKED(String, name, 1);
8643
8644 int index;
8645 PropertyAttributes attributes;
8646 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008647 BindingFlags binding_flags;
8648 Handle<Object> holder = context->Lookup(name,
8649 flags,
8650 &index,
8651 &attributes,
8652 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008653
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008654 // If the slot was not found the result is true.
8655 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008656 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008657 }
8658
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008659 // If the slot was found in a context, it should be DONT_DELETE.
8660 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008661 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008662 }
8663
8664 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008665 // the global object, or the subject of a with. Try to delete it
8666 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008667 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008668 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008669}
8670
8671
ager@chromium.orga1645e22009-09-09 19:27:10 +00008672// A mechanism to return a pair of Object pointers in registers (if possible).
8673// How this is achieved is calling convention-dependent.
8674// All currently supported x86 compiles uses calling conventions that are cdecl
8675// variants where a 64-bit value is returned in two 32-bit registers
8676// (edx:eax on ia32, r1:r0 on ARM).
8677// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8678// In Win64 calling convention, a struct of two pointers is returned in memory,
8679// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008680#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008681struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008682 MaybeObject* x;
8683 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008684};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008685
lrn@chromium.org303ada72010-10-27 09:33:13 +00008686static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008687 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008688 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8689 // In Win64 they are assigned to a hidden first argument.
8690 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008691}
8692#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008693typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008694static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008695 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008696 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008697}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008698#endif
8699
8700
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008701static inline MaybeObject* Unhole(Heap* heap,
8702 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008703 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008704 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8705 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008706 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707}
8708
8709
danno@chromium.org40cb8782011-05-25 07:58:50 +00008710static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8711 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008712 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008714 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008715 JSFunction* context_extension_function =
8716 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008717 // If the holder isn't a context extension object, we just return it
8718 // as the receiver. This allows arguments objects to be used as
8719 // receivers, but only if they are put in the context scope chain
8720 // explicitly via a with-statement.
8721 Object* constructor = holder->map()->constructor();
8722 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008723 // Fall back to using the global object as the implicit receiver if
8724 // the property turns out to be a local variable allocated in a
8725 // context extension object - introduced via eval. Implicit global
8726 // receivers are indicated with the hole value.
8727 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008728}
8729
8730
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008731static ObjectPair LoadContextSlotHelper(Arguments args,
8732 Isolate* isolate,
8733 bool throw_error) {
8734 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008735 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008736
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008737 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008738 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008739 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008740 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008741 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008742
8743 int index;
8744 PropertyAttributes attributes;
8745 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008746 BindingFlags binding_flags;
8747 Handle<Object> holder = context->Lookup(name,
8748 flags,
8749 &index,
8750 &attributes,
8751 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008752
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008753 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008754 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008755 ASSERT(holder->IsContext());
8756 // If the "property" we were looking for is a local variable, the
8757 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008758 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008759 // Use the hole as the receiver to signal that the receiver is implicit
8760 // and that the global receiver should be used (as distinguished from an
8761 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008762 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008763 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008764 // Check for uninitialized bindings.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008765 if (binding_flags == MUTABLE_CHECK_INITIALIZED && value->IsTheHole()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008766 Handle<Object> reference_error =
8767 isolate->factory()->NewReferenceError("not_defined",
8768 HandleVector(&name, 1));
8769 return MakePair(isolate->Throw(*reference_error), NULL);
8770 } else {
8771 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008773 }
8774
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008775 // Otherwise, if the slot was found the holder is a context extension
8776 // object, subject of a with, or a global object. We read the named
8777 // property from it.
8778 if (!holder.is_null()) {
8779 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8780 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008781 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008782 Handle<Object> receiver_handle(object->IsGlobalObject()
8783 ? GlobalObject::cast(*object)->global_receiver()
8784 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008785
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008786 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008787 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008788 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008789 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008790 }
8791
8792 if (throw_error) {
8793 // The property doesn't exist - throw exception.
8794 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008795 isolate->factory()->NewReferenceError("not_defined",
8796 HandleVector(&name, 1));
8797 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008798 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008799 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008800 return MakePair(isolate->heap()->undefined_value(),
8801 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008802 }
8803}
8804
8805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008806RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008807 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008808}
8809
8810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008811RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008812 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008813}
8814
8815
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008816RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008817 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008818 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008819
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008820 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008821 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008822 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008823 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008824 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8825 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008826 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008827
8828 int index;
8829 PropertyAttributes attributes;
8830 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008831 BindingFlags binding_flags;
8832 Handle<Object> holder = context->Lookup(name,
8833 flags,
8834 &index,
8835 &attributes,
8836 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008837
8838 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008839 // The property was found in a context slot.
8840 Handle<Context> context = Handle<Context>::cast(holder);
8841 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8842 context->get(index)->IsTheHole()) {
8843 Handle<Object> error =
8844 isolate->factory()->NewReferenceError("not_defined",
8845 HandleVector(&name, 1));
8846 return isolate->Throw(*error);
8847 }
8848 // Ignore if read_only variable.
8849 if ((attributes & READ_ONLY) == 0) {
8850 // Context is a fixed array and set cannot fail.
8851 context->set(index, *value);
8852 } else if (strict_mode == kStrictMode) {
8853 // Setting read only property in strict mode.
8854 Handle<Object> error =
8855 isolate->factory()->NewTypeError("strict_cannot_assign",
8856 HandleVector(&name, 1));
8857 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008858 }
8859 return *value;
8860 }
8861
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008862 // Slow case: The property is not in a context slot. It is either in a
8863 // context extension object, a property of the subject of a with, or a
8864 // property of the global object.
8865 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008867 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008868 // The property exists on the holder.
8869 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008870 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008871 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008872 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008873
8874 if (strict_mode == kStrictMode) {
8875 // Throw in strict mode (assignment to undefined variable).
8876 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008877 isolate->factory()->NewReferenceError(
8878 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008879 return isolate->Throw(*error);
8880 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008881 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008883 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008884 }
8885
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008886 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008887 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008888 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008889 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 isolate,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008891 SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008892 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008893 // Setting read only property in strict mode.
8894 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008895 isolate->factory()->NewTypeError(
8896 "strict_cannot_assign", HandleVector(&name, 1));
8897 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008898 }
8899 return *value;
8900}
8901
8902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008903RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008904 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008905 ASSERT(args.length() == 1);
8906
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008907 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008908}
8909
8910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008911RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008912 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008913 ASSERT(args.length() == 1);
8914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008915 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008916}
8917
8918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008919RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008920 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008921 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008922}
8923
8924
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008925RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008926 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008927 ASSERT(args.length() == 1);
8928
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008929 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008931 isolate->factory()->NewReferenceError("not_defined",
8932 HandleVector(&name, 1));
8933 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008934}
8935
8936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008937RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008938 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008939
8940 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 if (isolate->stack_guard()->IsStackOverflow()) {
8942 NoHandleAllocation na;
8943 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008944 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008945
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008946 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008947}
8948
8949
8950// NOTE: These PrintXXX functions are defined for all builds (not just
8951// DEBUG builds) because we may want to be able to trace function
8952// calls in all modes.
8953static void PrintString(String* str) {
8954 // not uncommon to have empty strings
8955 if (str->length() > 0) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00008956 SmartArrayPointer<char> s =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008957 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8958 PrintF("%s", *s);
8959 }
8960}
8961
8962
8963static void PrintObject(Object* obj) {
8964 if (obj->IsSmi()) {
8965 PrintF("%d", Smi::cast(obj)->value());
8966 } else if (obj->IsString() || obj->IsSymbol()) {
8967 PrintString(String::cast(obj));
8968 } else if (obj->IsNumber()) {
8969 PrintF("%g", obj->Number());
8970 } else if (obj->IsFailure()) {
8971 PrintF("<failure>");
8972 } else if (obj->IsUndefined()) {
8973 PrintF("<undefined>");
8974 } else if (obj->IsNull()) {
8975 PrintF("<null>");
8976 } else if (obj->IsTrue()) {
8977 PrintF("<true>");
8978 } else if (obj->IsFalse()) {
8979 PrintF("<false>");
8980 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008981 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008982 }
8983}
8984
8985
8986static int StackSize() {
8987 int n = 0;
8988 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8989 return n;
8990}
8991
8992
8993static void PrintTransition(Object* result) {
8994 // indentation
8995 { const int nmax = 80;
8996 int n = StackSize();
8997 if (n <= nmax)
8998 PrintF("%4d:%*s", n, n, "");
8999 else
9000 PrintF("%4d:%*s", n, nmax, "...");
9001 }
9002
9003 if (result == NULL) {
9004 // constructor calls
9005 JavaScriptFrameIterator it;
9006 JavaScriptFrame* frame = it.frame();
9007 if (frame->IsConstructor()) PrintF("new ");
9008 // function name
9009 Object* fun = frame->function();
9010 if (fun->IsJSFunction()) {
9011 PrintObject(JSFunction::cast(fun)->shared()->name());
9012 } else {
9013 PrintObject(fun);
9014 }
9015 // function arguments
9016 // (we are intentionally only printing the actually
9017 // supplied parameters, not all parameters required)
9018 PrintF("(this=");
9019 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009020 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009021 for (int i = 0; i < length; i++) {
9022 PrintF(", ");
9023 PrintObject(frame->GetParameter(i));
9024 }
9025 PrintF(") {\n");
9026
9027 } else {
9028 // function result
9029 PrintF("} -> ");
9030 PrintObject(result);
9031 PrintF("\n");
9032 }
9033}
9034
9035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009036RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009037 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009038 NoHandleAllocation ha;
9039 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009040 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009041}
9042
9043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009044RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009045 NoHandleAllocation ha;
9046 PrintTransition(args[0]);
9047 return args[0]; // return TOS
9048}
9049
9050
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009051RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052 NoHandleAllocation ha;
9053 ASSERT(args.length() == 1);
9054
9055#ifdef DEBUG
9056 if (args[0]->IsString()) {
9057 // If we have a string, assume it's a code "marker"
9058 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009059 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009060 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009061 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9062 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009063 } else {
9064 PrintF("DebugPrint: ");
9065 }
9066 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009067 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009068 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009069 HeapObject::cast(args[0])->map()->Print();
9070 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009071#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009072 // ShortPrint is available in release mode. Print is not.
9073 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009074#endif
9075 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009076 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009077
9078 return args[0]; // return TOS
9079}
9080
9081
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009082RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009083 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009084 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009085 isolate->PrintStack();
9086 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009087}
9088
9089
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009090RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009091 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009092 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093
9094 // According to ECMA-262, section 15.9.1, page 117, the precision of
9095 // the number in a Date object representing a particular instant in
9096 // time is milliseconds. Therefore, we floor the result of getting
9097 // the OS time.
9098 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009099 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009100}
9101
9102
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009103RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009104 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009105 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009106
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009107 CONVERT_ARG_CHECKED(String, str, 0);
9108 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009109
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009110 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009111
9112 MaybeObject* maybe_result_array =
9113 output->EnsureCanContainNonSmiElements();
9114 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009115 RUNTIME_ASSERT(output->HasFastElements());
9116
9117 AssertNoAllocation no_allocation;
9118
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009119 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009120 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9121 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009122 String::FlatContent str_content = str->GetFlatContent();
9123 if (str_content.IsAscii()) {
9124 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009125 output_array,
9126 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009128 ASSERT(str_content.IsTwoByte());
9129 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009130 output_array,
9131 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009132 }
9133
9134 if (result) {
9135 return *output;
9136 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009138 }
9139}
9140
9141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009142RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009143 NoHandleAllocation ha;
9144 ASSERT(args.length() == 1);
9145
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009146 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009147 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009148 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009149}
9150
9151
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009152RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009153 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009154 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009156 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009157}
9158
9159
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009160RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009161 NoHandleAllocation ha;
9162 ASSERT(args.length() == 1);
9163
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009164 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009165 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166}
9167
9168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009169RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009170 ASSERT(args.length() == 1);
9171 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009172 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009173 return JSGlobalObject::cast(global)->global_receiver();
9174}
9175
9176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009177RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009178 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009179 ASSERT_EQ(1, args.length());
9180 CONVERT_ARG_CHECKED(String, source, 0);
9181
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009182 source = Handle<String>(source->TryFlattenGetString());
9183 // Optimized fast case where we only have ascii characters.
9184 Handle<Object> result;
9185 if (source->IsSeqAsciiString()) {
9186 result = JsonParser<true>::Parse(source);
9187 } else {
9188 result = JsonParser<false>::Parse(source);
9189 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009190 if (result.is_null()) {
9191 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009192 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009193 return Failure::Exception();
9194 }
9195 return *result;
9196}
9197
9198
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009199bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9200 Handle<Context> context) {
9201 if (context->allow_code_gen_from_strings()->IsFalse()) {
9202 // Check with callback if set.
9203 AllowCodeGenerationFromStringsCallback callback =
9204 isolate->allow_code_gen_callback();
9205 if (callback == NULL) {
9206 // No callback set and code generation disallowed.
9207 return false;
9208 } else {
9209 // Callback set. Let it decide if code generation is allowed.
9210 VMState state(isolate, EXTERNAL);
9211 return callback(v8::Utils::ToLocal(context));
9212 }
9213 }
9214 return true;
9215}
9216
9217
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009218RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009219 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009220 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009221 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009222
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009223 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009224 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009225
9226 // Check if global context allows code generation from
9227 // strings. Throw an exception if it doesn't.
9228 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
9229 return isolate->Throw(*isolate->factory()->NewError(
9230 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9231 }
9232
9233 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009234 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9235 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009236 true,
9237 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009238 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009239 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9241 context,
9242 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009243 return *fun;
9244}
9245
9246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009247static ObjectPair CompileGlobalEval(Isolate* isolate,
9248 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009249 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009250 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009251 Handle<Context> context = Handle<Context>(isolate->context());
9252 Handle<Context> global_context = Handle<Context>(context->global_context());
9253
9254 // Check if global context allows code generation from
9255 // strings. Throw an exception if it doesn't.
9256 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9257 isolate->Throw(*isolate->factory()->NewError(
9258 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9259 return MakePair(Failure::Exception(), NULL);
9260 }
9261
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009262 // Deal with a normal eval call with a string argument. Compile it
9263 // and return the compiled function bound in the local context.
9264 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9265 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009266 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009267 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009268 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009269 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009270 Handle<JSFunction> compiled =
9271 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009272 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009273 return MakePair(*compiled, *receiver);
9274}
9275
9276
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009277RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009278 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009279
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009280 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009281 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009282 Handle<Object> receiver; // Will be overwritten.
9283
9284 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009285 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009286#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009287 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009288 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009289 StackFrameLocator locator;
9290 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009291 ASSERT(Context::cast(frame->context()) == *context);
9292#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009293
9294 // Find where the 'eval' symbol is bound. It is unaliased only if
9295 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009296 int index = -1;
9297 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009298 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009299 while (true) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009300 // Don't follow context chains in Context::Lookup and implement the loop
9301 // up the context chain here, so that we can know the context where eval
9302 // was found.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009303 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9304 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009305 &index,
9306 &attributes,
9307 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009308 // Stop search when eval is found or when the global context is
9309 // reached.
9310 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009311 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009312 }
9313
iposva@chromium.org245aa852009-02-10 00:49:54 +00009314 // If eval could not be resolved, it has been deleted and we need to
9315 // throw a reference error.
9316 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009317 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009318 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009319 isolate->factory()->NewReferenceError("not_defined",
9320 HandleVector(&name, 1));
9321 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009322 }
9323
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009324 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009325 // 'eval' is not bound in the global context. Just call the function
9326 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009327 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009328 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009329 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009330 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009331 }
9332
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009333 // 'eval' is bound in the global context, but it may have been overwritten.
9334 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009335 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009336 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009337 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009338 }
9339
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009340 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009341 return CompileGlobalEval(isolate,
9342 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009343 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009344 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009345}
9346
9347
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009348RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009349 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009351 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009352 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009353
9354 // 'eval' is bound in the global context, but it may have been overwritten.
9355 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009356 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009357 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009358 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009359 }
9360
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009361 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 return CompileGlobalEval(isolate,
9363 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009364 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009365 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009366}
9367
9368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009369RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009370 // This utility adjusts the property attributes for newly created Function
9371 // object ("new Function(...)") by changing the map.
9372 // All it does is changing the prototype property to enumerable
9373 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009374 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009375 ASSERT(args.length() == 1);
9376 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009377
9378 Handle<Map> map = func->shared()->strict_mode()
9379 ? isolate->strict_mode_function_instance_map()
9380 : isolate->function_instance_map();
9381
9382 ASSERT(func->map()->instance_type() == map->instance_type());
9383 ASSERT(func->map()->instance_size() == map->instance_size());
9384 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009385 return *func;
9386}
9387
9388
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009389RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009390 // Allocate a block of memory in NewSpace (filled with a filler).
9391 // Use as fallback for allocation in generated code when NewSpace
9392 // is full.
9393 ASSERT(args.length() == 1);
9394 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9395 int size = size_smi->value();
9396 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9397 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009398 Heap* heap = isolate->heap();
9399 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009400 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009401 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009402 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009403 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009404 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009405 }
9406 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009407 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009408}
9409
9410
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009411// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009412// array. Returns true if the element was pushed on the stack and
9413// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009414RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009415 ASSERT(args.length() == 2);
9416 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009417 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009418 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009419 int length = Smi::cast(array->length())->value();
9420 FixedArray* elements = FixedArray::cast(array->elements());
9421 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009422 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009423 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009424 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009425 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009426 { MaybeObject* maybe_obj =
9427 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009428 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9429 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009430 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009431}
9432
9433
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009434/**
9435 * A simple visitor visits every element of Array's.
9436 * The backend storage can be a fixed array for fast elements case,
9437 * or a dictionary for sparse array. Since Dictionary is a subtype
9438 * of FixedArray, the class can be used by both fast and slow cases.
9439 * The second parameter of the constructor, fast_elements, specifies
9440 * whether the storage is a FixedArray or Dictionary.
9441 *
9442 * An index limit is used to deal with the situation that a result array
9443 * length overflows 32-bit non-negative integer.
9444 */
9445class ArrayConcatVisitor {
9446 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009447 ArrayConcatVisitor(Isolate* isolate,
9448 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009449 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009450 isolate_(isolate),
9451 storage_(Handle<FixedArray>::cast(
9452 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009453 index_offset_(0u),
9454 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009455
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009456 ~ArrayConcatVisitor() {
9457 clear_storage();
9458 }
9459
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009460 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009461 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009462 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009463
9464 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009465 if (index < static_cast<uint32_t>(storage_->length())) {
9466 storage_->set(index, *elm);
9467 return;
9468 }
9469 // Our initial estimate of length was foiled, possibly by
9470 // getters on the arrays increasing the length of later arrays
9471 // during iteration.
9472 // This shouldn't happen in anything but pathological cases.
9473 SetDictionaryMode(index);
9474 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009475 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009476 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009477 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009478 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009479 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009480 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009481 // Dictionary needed to grow.
9482 clear_storage();
9483 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009484 }
9485}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009486
9487 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009488 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9489 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009490 } else {
9491 index_offset_ += delta;
9492 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009493 }
9494
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009495 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009496 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009497 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009498 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009499 Handle<Map> map;
9500 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009501 map = isolate_->factory()->GetElementsTransitionMap(array,
9502 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009503 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009504 map = isolate_->factory()->GetElementsTransitionMap(array,
9505 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009506 }
9507 array->set_map(*map);
9508 array->set_length(*length);
9509 array->set_elements(*storage_);
9510 return array;
9511 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009512
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009513 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009514 // Convert storage to dictionary mode.
9515 void SetDictionaryMode(uint32_t index) {
9516 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009517 Handle<FixedArray> current_storage(*storage_);
9518 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009519 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009520 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9521 for (uint32_t i = 0; i < current_length; i++) {
9522 HandleScope loop_scope;
9523 Handle<Object> element(current_storage->get(i));
9524 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009525 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009526 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009527 if (!new_storage.is_identical_to(slow_storage)) {
9528 slow_storage = loop_scope.CloseAndEscape(new_storage);
9529 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009530 }
9531 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009532 clear_storage();
9533 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009534 fast_elements_ = false;
9535 }
9536
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009537 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009538 isolate_->global_handles()->Destroy(
9539 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009540 }
9541
9542 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009543 storage_ = Handle<FixedArray>::cast(
9544 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009545 }
9546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009547 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009548 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009549 // Index after last seen index. Always less than or equal to
9550 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009551 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009552 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009553};
9554
9555
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009556static uint32_t EstimateElementCount(Handle<JSArray> array) {
9557 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9558 int element_count = 0;
9559 switch (array->GetElementsKind()) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009560 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009561 // Fast elements can't have lengths that are not representable by
9562 // a 32-bit signed integer.
9563 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9564 int fast_length = static_cast<int>(length);
9565 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9566 for (int i = 0; i < fast_length; i++) {
9567 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009568 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009569 break;
9570 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009571 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009572 Handle<NumberDictionary> dictionary(
9573 NumberDictionary::cast(array->elements()));
9574 int capacity = dictionary->Capacity();
9575 for (int i = 0; i < capacity; i++) {
9576 Handle<Object> key(dictionary->KeyAt(i));
9577 if (dictionary->IsKey(*key)) {
9578 element_count++;
9579 }
9580 }
9581 break;
9582 }
9583 default:
9584 // External arrays are always dense.
9585 return length;
9586 }
9587 // As an estimate, we assume that the prototype doesn't contain any
9588 // inherited elements.
9589 return element_count;
9590}
9591
9592
9593
9594template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009595static void IterateExternalArrayElements(Isolate* isolate,
9596 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009597 bool elements_are_ints,
9598 bool elements_are_guaranteed_smis,
9599 ArrayConcatVisitor* visitor) {
9600 Handle<ExternalArrayClass> array(
9601 ExternalArrayClass::cast(receiver->elements()));
9602 uint32_t len = static_cast<uint32_t>(array->length());
9603
9604 ASSERT(visitor != NULL);
9605 if (elements_are_ints) {
9606 if (elements_are_guaranteed_smis) {
9607 for (uint32_t j = 0; j < len; j++) {
9608 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009609 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009610 visitor->visit(j, e);
9611 }
9612 } else {
9613 for (uint32_t j = 0; j < len; j++) {
9614 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009615 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009616 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9617 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9618 visitor->visit(j, e);
9619 } else {
9620 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009621 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009622 visitor->visit(j, e);
9623 }
9624 }
9625 }
9626 } else {
9627 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009628 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009629 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009630 visitor->visit(j, e);
9631 }
9632 }
9633}
9634
9635
9636// Used for sorting indices in a List<uint32_t>.
9637static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9638 uint32_t a = *ap;
9639 uint32_t b = *bp;
9640 return (a == b) ? 0 : (a < b) ? -1 : 1;
9641}
9642
9643
9644static void CollectElementIndices(Handle<JSObject> object,
9645 uint32_t range,
9646 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009647 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009649 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009650 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009651 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9652 uint32_t length = static_cast<uint32_t>(elements->length());
9653 if (range < length) length = range;
9654 for (uint32_t i = 0; i < length; i++) {
9655 if (!elements->get(i)->IsTheHole()) {
9656 indices->Add(i);
9657 }
9658 }
9659 break;
9660 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009661 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009662 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009663 uint32_t capacity = dict->Capacity();
9664 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009665 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009666 Handle<Object> k(dict->KeyAt(j));
9667 if (dict->IsKey(*k)) {
9668 ASSERT(k->IsNumber());
9669 uint32_t index = static_cast<uint32_t>(k->Number());
9670 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009671 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009672 }
9673 }
9674 }
9675 break;
9676 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009677 default: {
9678 int dense_elements_length;
9679 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009680 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009681 dense_elements_length =
9682 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009683 break;
9684 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009685 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009686 dense_elements_length =
9687 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009688 break;
9689 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009690 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009691 dense_elements_length =
9692 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009693 break;
9694 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009695 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009696 dense_elements_length =
9697 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009698 break;
9699 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009700 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009701 dense_elements_length =
9702 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009703 break;
9704 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009705 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009706 dense_elements_length =
9707 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009708 break;
9709 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009710 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009711 dense_elements_length =
9712 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009713 break;
9714 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009715 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009716 dense_elements_length =
9717 ExternalFloatArray::cast(object->elements())->length();
9718 break;
9719 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009720 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009721 dense_elements_length =
9722 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009723 break;
9724 }
9725 default:
9726 UNREACHABLE();
9727 dense_elements_length = 0;
9728 break;
9729 }
9730 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9731 if (range <= length) {
9732 length = range;
9733 // We will add all indices, so we might as well clear it first
9734 // and avoid duplicates.
9735 indices->Clear();
9736 }
9737 for (uint32_t i = 0; i < length; i++) {
9738 indices->Add(i);
9739 }
9740 if (length == range) return; // All indices accounted for already.
9741 break;
9742 }
9743 }
9744
9745 Handle<Object> prototype(object->GetPrototype());
9746 if (prototype->IsJSObject()) {
9747 // The prototype will usually have no inherited element indices,
9748 // but we have to check.
9749 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9750 }
9751}
9752
9753
9754/**
9755 * A helper function that visits elements of a JSArray in numerical
9756 * order.
9757 *
9758 * The visitor argument called for each existing element in the array
9759 * with the element index and the element's value.
9760 * Afterwards it increments the base-index of the visitor by the array
9761 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009762 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009763 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009764static bool IterateElements(Isolate* isolate,
9765 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009766 ArrayConcatVisitor* visitor) {
9767 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9768 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009769 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009770 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009771 // Run through the elements FixedArray and use HasElement and GetElement
9772 // to check the prototype for missing elements.
9773 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9774 int fast_length = static_cast<int>(length);
9775 ASSERT(fast_length <= elements->length());
9776 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009777 HandleScope loop_scope(isolate);
9778 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009779 if (!element_value->IsTheHole()) {
9780 visitor->visit(j, element_value);
9781 } else if (receiver->HasElement(j)) {
9782 // Call GetElement on receiver, not its prototype, or getters won't
9783 // have the correct receiver.
9784 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009785 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009786 visitor->visit(j, element_value);
9787 }
9788 }
9789 break;
9790 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009791 case DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009792 Handle<NumberDictionary> dict(receiver->element_dictionary());
9793 List<uint32_t> indices(dict->Capacity() / 2);
9794 // Collect all indices in the object and the prototypes less
9795 // than length. This might introduce duplicates in the indices list.
9796 CollectElementIndices(receiver, length, &indices);
9797 indices.Sort(&compareUInt32);
9798 int j = 0;
9799 int n = indices.length();
9800 while (j < n) {
9801 HandleScope loop_scope;
9802 uint32_t index = indices[j];
9803 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009804 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009805 visitor->visit(index, element);
9806 // Skip to next different index (i.e., omit duplicates).
9807 do {
9808 j++;
9809 } while (j < n && indices[j] == index);
9810 }
9811 break;
9812 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009813 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009814 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9815 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009816 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009817 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009818 visitor->visit(j, e);
9819 }
9820 break;
9821 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009822 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009823 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009825 break;
9826 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009827 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009828 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009830 break;
9831 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009832 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009833 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009834 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009835 break;
9836 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009837 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009838 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009839 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009840 break;
9841 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009842 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009843 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009844 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009845 break;
9846 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009847 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009848 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009849 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009850 break;
9851 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009852 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009853 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009854 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009855 break;
9856 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009857 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009858 IterateExternalArrayElements<ExternalDoubleArray, double>(
9859 isolate, receiver, false, false, visitor);
9860 break;
9861 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009862 default:
9863 UNREACHABLE();
9864 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009865 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009866 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009867 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009868}
9869
9870
9871/**
9872 * Array::concat implementation.
9873 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009874 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009875 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009876 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009877RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009878 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009879 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009880
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009881 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9882 int argument_count = static_cast<int>(arguments->length()->Number());
9883 RUNTIME_ASSERT(arguments->HasFastElements());
9884 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009885
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009886 // Pass 1: estimate the length and number of elements of the result.
9887 // The actual length can be larger if any of the arguments have getters
9888 // that mutate other arguments (but will otherwise be precise).
9889 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009890
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009891 uint32_t estimate_result_length = 0;
9892 uint32_t estimate_nof_elements = 0;
9893 {
9894 for (int i = 0; i < argument_count; i++) {
9895 HandleScope loop_scope;
9896 Handle<Object> obj(elements->get(i));
9897 uint32_t length_estimate;
9898 uint32_t element_estimate;
9899 if (obj->IsJSArray()) {
9900 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9901 length_estimate =
9902 static_cast<uint32_t>(array->length()->Number());
9903 element_estimate =
9904 EstimateElementCount(array);
9905 } else {
9906 length_estimate = 1;
9907 element_estimate = 1;
9908 }
9909 // Avoid overflows by capping at kMaxElementCount.
9910 if (JSObject::kMaxElementCount - estimate_result_length <
9911 length_estimate) {
9912 estimate_result_length = JSObject::kMaxElementCount;
9913 } else {
9914 estimate_result_length += length_estimate;
9915 }
9916 if (JSObject::kMaxElementCount - estimate_nof_elements <
9917 element_estimate) {
9918 estimate_nof_elements = JSObject::kMaxElementCount;
9919 } else {
9920 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009921 }
9922 }
9923 }
9924
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009925 // If estimated number of elements is more than half of length, a
9926 // fixed array (fast case) is more time and space-efficient than a
9927 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009928 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009929
9930 Handle<FixedArray> storage;
9931 if (fast_case) {
9932 // The backing storage array must have non-existing elements to
9933 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009934 storage = isolate->factory()->NewFixedArrayWithHoles(
9935 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009936 } else {
9937 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9938 uint32_t at_least_space_for = estimate_nof_elements +
9939 (estimate_nof_elements >> 2);
9940 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009941 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009942 }
9943
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009944 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009945
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009946 for (int i = 0; i < argument_count; i++) {
9947 Handle<Object> obj(elements->get(i));
9948 if (obj->IsJSArray()) {
9949 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009950 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009951 return Failure::Exception();
9952 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009953 } else {
9954 visitor.visit(0, obj);
9955 visitor.increase_index_offset(1);
9956 }
9957 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009958
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009959 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009960}
9961
9962
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009963// This will not allocate (flatten the string), but it may run
9964// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009965RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009966 NoHandleAllocation ha;
9967 ASSERT(args.length() == 1);
9968
9969 CONVERT_CHECKED(String, string, args[0]);
9970 StringInputBuffer buffer(string);
9971 while (buffer.has_more()) {
9972 uint16_t character = buffer.GetNext();
9973 PrintF("%c", character);
9974 }
9975 return string;
9976}
9977
ager@chromium.org5ec48922009-05-05 07:25:34 +00009978// Moves all own elements of an object, that are below a limit, to positions
9979// starting at zero. All undefined values are placed after non-undefined values,
9980// and are followed by non-existing element. Does not change the length
9981// property.
9982// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009983RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009984 ASSERT(args.length() == 2);
9985 CONVERT_CHECKED(JSObject, object, args[0]);
9986 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9987 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009988}
9989
9990
9991// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009992RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 ASSERT(args.length() == 2);
9994 CONVERT_CHECKED(JSArray, from, args[0]);
9995 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009996 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009997 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009998 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009999 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10000 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010001 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010002 } else if (new_elements->map() ==
10003 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010004 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010005 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010006 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010007 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010008 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010009 Object* new_map;
10010 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010011 to->set_map(Map::cast(new_map));
10012 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010013 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010014 Object* obj;
10015 { MaybeObject* maybe_obj = from->ResetElements();
10016 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10017 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010018 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019 return to;
10020}
10021
10022
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010023// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010024RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010025 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010026 CONVERT_CHECKED(JSObject, object, args[0]);
10027 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010028 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000010029 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010030 } else if (object->IsJSArray()) {
10031 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010033 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010034 }
10035}
10036
10037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010038RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010039 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010040
10041 ASSERT_EQ(3, args.length());
10042
ager@chromium.orgac091b72010-05-05 07:34:42 +000010043 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010044 Handle<Object> key1 = args.at<Object>(1);
10045 Handle<Object> key2 = args.at<Object>(2);
10046
10047 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010048 if (!key1->ToArrayIndex(&index1)
10049 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010050 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010051 }
10052
ager@chromium.orgac091b72010-05-05 07:34:42 +000010053 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
10054 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010056 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010057 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010058
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010059 RETURN_IF_EMPTY_HANDLE(isolate,
10060 SetElement(jsobject, index1, tmp2, kStrictMode));
10061 RETURN_IF_EMPTY_HANDLE(isolate,
10062 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010064 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010065}
10066
10067
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010068// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010069// might have elements. Can either return keys (positive integers) or
10070// intervals (pair of a negative integer (-start-1) followed by a
10071// positive (length)) or undefined values.
10072// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010073RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010074 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010075 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010076 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010077 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010078 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010079 // Create an array and get all the keys into it, then remove all the
10080 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010081 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010082 int keys_length = keys->length();
10083 for (int i = 0; i < keys_length; i++) {
10084 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010085 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010086 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010087 // Zap invalid keys.
10088 keys->set_undefined(i);
10089 }
10090 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010091 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010092 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010093 ASSERT(array->HasFastElements() ||
10094 array->HasFastSmiOnlyElements() ||
10095 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010096 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010097 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010098 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010099 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010100 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010101 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010102 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010103 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010104 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010105 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010106 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010107 }
10108}
10109
10110
10111// DefineAccessor takes an optional final argument which is the
10112// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10113// to the way accessors are implemented, it is set for both the getter
10114// and setter on the first call to DefineAccessor and ignored on
10115// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010116RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010117 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10118 // Compute attributes.
10119 PropertyAttributes attributes = NONE;
10120 if (args.length() == 5) {
10121 CONVERT_CHECKED(Smi, attrs, args[4]);
10122 int value = attrs->value();
10123 // Only attribute bits should be set.
10124 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10125 attributes = static_cast<PropertyAttributes>(value);
10126 }
10127
10128 CONVERT_CHECKED(JSObject, obj, args[0]);
10129 CONVERT_CHECKED(String, name, args[1]);
10130 CONVERT_CHECKED(Smi, flag, args[2]);
10131 CONVERT_CHECKED(JSFunction, fun, args[3]);
10132 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10133}
10134
10135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010136RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137 ASSERT(args.length() == 3);
10138 CONVERT_CHECKED(JSObject, obj, args[0]);
10139 CONVERT_CHECKED(String, name, args[1]);
10140 CONVERT_CHECKED(Smi, flag, args[2]);
10141 return obj->LookupAccessor(name, flag->value() == 0);
10142}
10143
10144
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010145#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010146RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010147 ASSERT(args.length() == 0);
10148 return Execution::DebugBreakHelper();
10149}
10150
10151
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152// Helper functions for wrapping and unwrapping stack frame ids.
10153static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010154 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010155 return Smi::FromInt(id >> 2);
10156}
10157
10158
10159static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10160 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10161}
10162
10163
10164// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010165// args[0]: debug event listener function to set or null or undefined for
10166// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010167// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010168RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010169 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010170 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10171 args[0]->IsUndefined() ||
10172 args[0]->IsNull());
10173 Handle<Object> callback = args.at<Object>(0);
10174 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010175 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010177 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010178}
10179
10180
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010181RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010182 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010183 isolate->stack_guard()->DebugBreak();
10184 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010185}
10186
10187
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010188static MaybeObject* DebugLookupResultValue(Heap* heap,
10189 Object* receiver,
10190 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010191 LookupResult* result,
10192 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010193 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010194 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010195 case NORMAL:
10196 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010197 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010198 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010199 }
10200 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010201 case FIELD:
10202 value =
10203 JSObject::cast(
10204 result->holder())->FastPropertyAt(result->GetFieldIndex());
10205 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010206 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010207 }
10208 return value;
10209 case CONSTANT_FUNCTION:
10210 return result->GetConstantFunction();
10211 case CALLBACKS: {
10212 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010213 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010214 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10215 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010216 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010217 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010218 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010219 maybe_value = heap->isolate()->pending_exception();
10220 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010221 if (caught_exception != NULL) {
10222 *caught_exception = true;
10223 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010224 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010225 }
10226 return value;
10227 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010228 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010229 }
10230 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010231 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010232 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010233 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010234 case CONSTANT_TRANSITION:
10235 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010236 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010237 default:
10238 UNREACHABLE();
10239 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010240 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010241 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010242}
10243
10244
ager@chromium.org32912102009-01-16 10:38:43 +000010245// Get debugger related details for an object property.
10246// args[0]: object holding property
10247// args[1]: name of the property
10248//
10249// The array returned contains the following information:
10250// 0: Property value
10251// 1: Property details
10252// 2: Property value is exception
10253// 3: Getter function if defined
10254// 4: Setter function if defined
10255// Items 2-4 are only filled if the property has either a getter or a setter
10256// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010257RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010258 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010259
10260 ASSERT(args.length() == 2);
10261
10262 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10263 CONVERT_ARG_CHECKED(String, name, 1);
10264
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010265 // Make sure to set the current context to the context before the debugger was
10266 // entered (if the debugger is entered). The reason for switching context here
10267 // is that for some property lookups (accessors and interceptors) callbacks
10268 // into the embedding application can occour, and the embedding application
10269 // could have the assumption that its own global context is the current
10270 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 SaveContext save(isolate);
10272 if (isolate->debug()->InDebugger()) {
10273 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010274 }
10275
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010276 // Skip the global proxy as it has no properties and always delegates to the
10277 // real global object.
10278 if (obj->IsJSGlobalProxy()) {
10279 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10280 }
10281
10282
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010283 // Check if the name is trivially convertible to an index and get the element
10284 // if so.
10285 uint32_t index;
10286 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010287 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010288 Object* element_or_char;
10289 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010290 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010291 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10292 return maybe_element_or_char;
10293 }
10294 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010295 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010296 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010297 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010298 }
10299
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010300 // Find the number of objects making up this.
10301 int length = LocalPrototypeChainLength(*obj);
10302
10303 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010304 Handle<JSObject> jsproto = obj;
10305 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010306 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010307 jsproto->LocalLookup(*name, &result);
10308 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010309 // LookupResult is not GC safe as it holds raw object pointers.
10310 // GC can happen later in this code so put the required fields into
10311 // local variables using handles when required for later use.
10312 PropertyType result_type = result.type();
10313 Handle<Object> result_callback_obj;
10314 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010315 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10316 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010317 }
10318 Smi* property_details = result.GetPropertyDetails().AsSmi();
10319 // DebugLookupResultValue can cause GC so details from LookupResult needs
10320 // to be copied to handles before this.
10321 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010322 Object* raw_value;
10323 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010324 DebugLookupResultValue(isolate->heap(), *obj, *name,
10325 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010326 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10327 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010328 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010329
10330 // If the callback object is a fixed array then it contains JavaScript
10331 // getter and/or setter.
10332 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10333 result_callback_obj->IsFixedArray();
10334 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010335 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010336 details->set(0, *value);
10337 details->set(1, property_details);
10338 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010339 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010340 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10341 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10342 }
10343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010344 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010345 }
10346 if (i < length - 1) {
10347 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10348 }
10349 }
10350
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352}
10353
10354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010355RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010356 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357
10358 ASSERT(args.length() == 2);
10359
10360 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10361 CONVERT_ARG_CHECKED(String, name, 1);
10362
10363 LookupResult result;
10364 obj->Lookup(*name, &result);
10365 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010366 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010367 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010368 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010369}
10370
10371
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010372// Return the property type calculated from the property details.
10373// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010374RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010375 ASSERT(args.length() == 1);
10376 CONVERT_CHECKED(Smi, details, args[0]);
10377 PropertyType type = PropertyDetails(details).type();
10378 return Smi::FromInt(static_cast<int>(type));
10379}
10380
10381
10382// Return the property attribute calculated from the property details.
10383// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010384RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010385 ASSERT(args.length() == 1);
10386 CONVERT_CHECKED(Smi, details, args[0]);
10387 PropertyAttributes attributes = PropertyDetails(details).attributes();
10388 return Smi::FromInt(static_cast<int>(attributes));
10389}
10390
10391
10392// Return the property insertion index calculated from the property details.
10393// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010394RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010395 ASSERT(args.length() == 1);
10396 CONVERT_CHECKED(Smi, details, args[0]);
10397 int index = PropertyDetails(details).index();
10398 return Smi::FromInt(index);
10399}
10400
10401
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402// Return property value from named interceptor.
10403// args[0]: object
10404// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010405RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010406 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 ASSERT(args.length() == 2);
10408 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10409 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10410 CONVERT_ARG_CHECKED(String, name, 1);
10411
10412 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010413 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010414}
10415
10416
10417// Return element value from indexed interceptor.
10418// args[0]: object
10419// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010420RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010421 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010422 ASSERT(args.length() == 2);
10423 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10424 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10425 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10426
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010427 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010428}
10429
10430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010431RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010432 ASSERT(args.length() >= 1);
10433 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010434 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010435 if (isolate->debug()->break_id() == 0 ||
10436 break_id != isolate->debug()->break_id()) {
10437 return isolate->Throw(
10438 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010439 }
10440
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010441 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010442}
10443
10444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010445RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010446 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010447 ASSERT(args.length() == 1);
10448
10449 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010450 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010451 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10452 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010453 if (!maybe_result->ToObject(&result)) return maybe_result;
10454 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010455
10456 // Count all frames which are relevant to debugging stack trace.
10457 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010458 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010459 if (id == StackFrame::NO_ID) {
10460 // If there is no JavaScript stack frame count is 0.
10461 return Smi::FromInt(0);
10462 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010463
10464 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10465 n += it.frame()->GetInlineCount();
10466 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010467 return Smi::FromInt(n);
10468}
10469
10470
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010471class FrameInspector {
10472 public:
10473 FrameInspector(JavaScriptFrame* frame,
10474 int inlined_frame_index,
10475 Isolate* isolate)
10476 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10477 // Calculate the deoptimized frame.
10478 if (frame->is_optimized()) {
10479 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10480 frame, inlined_frame_index, isolate);
10481 }
10482 has_adapted_arguments_ = frame_->has_adapted_arguments();
10483 is_optimized_ = frame_->is_optimized();
10484 }
10485
10486 ~FrameInspector() {
10487 // Get rid of the calculated deoptimized frame if any.
10488 if (deoptimized_frame_ != NULL) {
10489 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10490 isolate_);
10491 }
10492 }
10493
10494 int GetParametersCount() {
10495 return is_optimized_
10496 ? deoptimized_frame_->parameters_count()
10497 : frame_->ComputeParametersCount();
10498 }
10499 int expression_count() { return deoptimized_frame_->expression_count(); }
10500 Object* GetFunction() {
10501 return is_optimized_
10502 ? deoptimized_frame_->GetFunction()
10503 : frame_->function();
10504 }
10505 Object* GetParameter(int index) {
10506 return is_optimized_
10507 ? deoptimized_frame_->GetParameter(index)
10508 : frame_->GetParameter(index);
10509 }
10510 Object* GetExpression(int index) {
10511 return is_optimized_
10512 ? deoptimized_frame_->GetExpression(index)
10513 : frame_->GetExpression(index);
10514 }
10515
10516 // To inspect all the provided arguments the frame might need to be
10517 // replaced with the arguments frame.
10518 void SetArgumentsFrame(JavaScriptFrame* frame) {
10519 ASSERT(has_adapted_arguments_);
10520 frame_ = frame;
10521 is_optimized_ = frame_->is_optimized();
10522 ASSERT(!is_optimized_);
10523 }
10524
10525 private:
10526 JavaScriptFrame* frame_;
10527 DeoptimizedFrameInfo* deoptimized_frame_;
10528 Isolate* isolate_;
10529 bool is_optimized_;
10530 bool has_adapted_arguments_;
10531
10532 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10533};
10534
10535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010536static const int kFrameDetailsFrameIdIndex = 0;
10537static const int kFrameDetailsReceiverIndex = 1;
10538static const int kFrameDetailsFunctionIndex = 2;
10539static const int kFrameDetailsArgumentCountIndex = 3;
10540static const int kFrameDetailsLocalCountIndex = 4;
10541static const int kFrameDetailsSourcePositionIndex = 5;
10542static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010543static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010544static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010545static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010546
10547// Return an array with frame details
10548// args[0]: number: break id
10549// args[1]: number: frame index
10550//
10551// The array returned contains the following information:
10552// 0: Frame id
10553// 1: Receiver
10554// 2: Function
10555// 3: Argument count
10556// 4: Local count
10557// 5: Source position
10558// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010559// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010560// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010561// Arguments name, value
10562// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010563// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010564RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010566 ASSERT(args.length() == 2);
10567
10568 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010569 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010570 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10571 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010572 if (!maybe_check->ToObject(&check)) return maybe_check;
10573 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010574 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010575 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010576
10577 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010578 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010579 if (id == StackFrame::NO_ID) {
10580 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010581 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010582 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010583
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010584 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010585
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010586 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010587 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010588 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010589 if (index < count + it.frame()->GetInlineCount()) break;
10590 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010592 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010594 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010595 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010596 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010597 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010598 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600 // Traverse the saved contexts chain to find the active context for the
10601 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010602 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010603 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604 save = save->prev();
10605 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010606 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010607
10608 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010609 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010610
10611 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010612 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010613 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010614
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010615 // Check for constructor frame. Inlined frames cannot be construct calls.
10616 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010617 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010618 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010619
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010620 // Get scope info and read from it for local variable information.
10621 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010622 Handle<SharedFunctionInfo> shared(function->shared());
10623 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010624 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010625 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010627 // Get the locals names and values into a temporary array.
10628 //
10629 // TODO(1240907): Hide compiler-introduced stack variables
10630 // (e.g. .result)? For users of the debugger, they will probably be
10631 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010632 Handle<FixedArray> locals =
10633 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010634
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010635 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010636 int i = 0;
10637 for (; i < info.number_of_stack_slots(); ++i) {
10638 // Use the value from the stack.
10639 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010640 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010641 }
10642 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010643 // Get the context containing declarations.
10644 Handle<Context> context(
10645 Context::cast(it.frame()->context())->declaration_context());
10646 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010647 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010648 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010649 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010650 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010651 }
10652 }
10653
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010654 // Check whether this frame is positioned at return. If not top
10655 // frame or if the frame is optimized it cannot be at a return.
10656 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010657 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010658 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010659 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010660
10661 // If positioned just before return find the value to be returned and add it
10662 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010663 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010664 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010665 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010666 Address internal_frame_sp = NULL;
10667 while (!it2.done()) {
10668 if (it2.frame()->is_internal()) {
10669 internal_frame_sp = it2.frame()->sp();
10670 } else {
10671 if (it2.frame()->is_java_script()) {
10672 if (it2.frame()->id() == it.frame()->id()) {
10673 // The internal frame just before the JavaScript frame contains the
10674 // value to return on top. A debug break at return will create an
10675 // internal frame to store the return value (eax/rax/r0) before
10676 // entering the debug break exit frame.
10677 if (internal_frame_sp != NULL) {
10678 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010679 Handle<Object>(Memory::Object_at(internal_frame_sp),
10680 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010681 break;
10682 }
10683 }
10684 }
10685
10686 // Indicate that the previous frame was not an internal frame.
10687 internal_frame_sp = NULL;
10688 }
10689 it2.Advance();
10690 }
10691 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010692
10693 // Now advance to the arguments adapter frame (if any). It contains all
10694 // the provided parameters whereas the function frame always have the number
10695 // of arguments matching the functions parameters. The rest of the
10696 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010697 if (it.frame()->has_adapted_arguments()) {
10698 it.AdvanceToArgumentsFrame();
10699 frame_inspector.SetArgumentsFrame(it.frame());
10700 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010701
10702 // Find the number of arguments to fill. At least fill the number of
10703 // parameters for the function and fill more if more parameters are provided.
10704 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010705 if (argument_count < frame_inspector.GetParametersCount()) {
10706 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010707 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010708#ifdef DEBUG
10709 if (it.frame()->is_optimized()) {
10710 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10711 }
10712#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010713
10714 // Calculate the size of the result.
10715 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010716 2 * (argument_count + info.NumberOfLocals()) +
10717 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010718 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010719
10720 // Add the frame id.
10721 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10722
10723 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010724 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010725
10726 // Add the arguments count.
10727 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10728
10729 // Add the locals count
10730 details->set(kFrameDetailsLocalCountIndex,
10731 Smi::FromInt(info.NumberOfLocals()));
10732
10733 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010734 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10736 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010737 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010738 }
10739
10740 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010741 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010742
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010743 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010744 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010745
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010746 // Add flags to indicate information on whether this frame is
10747 // bit 0: invoked in the debugger context.
10748 // bit 1: optimized frame.
10749 // bit 2: inlined in optimized frame
10750 int flags = 0;
10751 if (*save->context() == *isolate->debug()->debug_context()) {
10752 flags |= 1 << 0;
10753 }
10754 if (it.frame()->is_optimized()) {
10755 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010756 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010757 }
10758 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010759
10760 // Fill the dynamic part.
10761 int details_index = kFrameDetailsFirstDynamicIndex;
10762
10763 // Add arguments name and value.
10764 for (int i = 0; i < argument_count; i++) {
10765 // Name of the argument.
10766 if (i < info.number_of_parameters()) {
10767 details->set(details_index++, *info.parameter_name(i));
10768 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010770 }
10771
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010772 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010773 if (i < it.frame()->ComputeParametersCount()) {
10774 // Get the value from the stack.
10775 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010777 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010778 }
10779 }
10780
10781 // Add locals name and value from the temporary copy from the function frame.
10782 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10783 details->set(details_index++, locals->get(i));
10784 }
10785
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010786 // Add the value being returned.
10787 if (at_return) {
10788 details->set(details_index++, *return_value);
10789 }
10790
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010791 // Add the receiver (same as in function frame).
10792 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10793 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010794 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010795 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10796 // If the receiver is not a JSObject and the function is not a
10797 // builtin or strict-mode we have hit an optimization where a
10798 // value object is not converted into a wrapped JS objects. To
10799 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800 // by creating correct wrapper object based on the calling frame's
10801 // global context.
10802 it.Advance();
10803 Handle<Context> calling_frames_global_context(
10804 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010805 receiver =
10806 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807 }
10808 details->set(kFrameDetailsReceiverIndex, *receiver);
10809
10810 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010811 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010812}
10813
10814
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010815// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010816static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010817 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010818 Handle<SerializedScopeInfo> serialized_scope_info,
10819 ScopeInfo<>& scope_info,
10820 Handle<Context> context,
10821 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010822 // Fill all context locals to the context extension.
10823 for (int i = Context::MIN_CONTEXT_SLOTS;
10824 i < scope_info.number_of_context_slots();
10825 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010826 int context_index = serialized_scope_info->ContextSlotIndex(
10827 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010828
whesse@chromium.org7b260152011-06-20 15:33:18 +000010829 RETURN_IF_EMPTY_HANDLE_VALUE(
10830 isolate,
10831 SetProperty(scope_object,
10832 scope_info.context_slot_name(i),
10833 Handle<Object>(context->get(context_index), isolate),
10834 NONE,
10835 kNonStrictMode),
10836 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010837 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010838
10839 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010840}
10841
10842
10843// Create a plain JSObject which materializes the local scope for the specified
10844// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010845static Handle<JSObject> MaterializeLocalScope(
10846 Isolate* isolate,
10847 JavaScriptFrame* frame,
10848 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010849 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010850 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010851 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10852 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010853 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010854
10855 // Allocate and initialize a JSObject with all the arguments, stack locals
10856 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010857 Handle<JSObject> local_scope =
10858 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010859
10860 // First fill all parameters.
10861 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010862 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010863 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010864 SetProperty(local_scope,
10865 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010866 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010867 NONE,
10868 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010869 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010870 }
10871
10872 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010873 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010874 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010875 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010876 SetProperty(local_scope,
10877 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010878 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010879 NONE,
10880 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010881 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010882 }
10883
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010884 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10885 // Third fill all context locals.
10886 Handle<Context> frame_context(Context::cast(frame->context()));
10887 Handle<Context> function_context(frame_context->declaration_context());
10888 if (!CopyContextLocalsToScopeObject(isolate,
10889 serialized_scope_info, scope_info,
10890 function_context, local_scope)) {
10891 return Handle<JSObject>();
10892 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010893
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010894 // Finally copy any properties from the function context extension.
10895 // These will be variables introduced by eval.
10896 if (function_context->closure() == *function) {
10897 if (function_context->has_extension() &&
10898 !function_context->IsGlobalContext()) {
10899 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10900 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10901 for (int i = 0; i < keys->length(); i++) {
10902 // Names of variables introduced by eval are strings.
10903 ASSERT(keys->get(i)->IsString());
10904 Handle<String> key(String::cast(keys->get(i)));
10905 RETURN_IF_EMPTY_HANDLE_VALUE(
10906 isolate,
10907 SetProperty(local_scope,
10908 key,
10909 GetProperty(ext, key),
10910 NONE,
10911 kNonStrictMode),
10912 Handle<JSObject>());
10913 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010914 }
10915 }
10916 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010917
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010918 return local_scope;
10919}
10920
10921
10922// Create a plain JSObject which materializes the closure content for the
10923// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010924static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10925 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010926 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010927
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010928 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010929 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10930 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010931
10932 // Allocate and initialize a JSObject with all the content of theis function
10933 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010934 Handle<JSObject> closure_scope =
10935 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010936
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010937 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010938 if (!CopyContextLocalsToScopeObject(isolate,
10939 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010940 context, closure_scope)) {
10941 return Handle<JSObject>();
10942 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010943
10944 // Finally copy any properties from the function context extension. This will
10945 // be variables introduced by eval.
10946 if (context->has_extension()) {
10947 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010948 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010949 for (int i = 0; i < keys->length(); i++) {
10950 // Names of variables introduced by eval are strings.
10951 ASSERT(keys->get(i)->IsString());
10952 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010953 RETURN_IF_EMPTY_HANDLE_VALUE(
10954 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010955 SetProperty(closure_scope,
10956 key,
10957 GetProperty(ext, key),
10958 NONE,
10959 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010960 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010961 }
10962 }
10963
10964 return closure_scope;
10965}
10966
10967
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010968// Create a plain JSObject which materializes the scope for the specified
10969// catch context.
10970static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10971 Handle<Context> context) {
10972 ASSERT(context->IsCatchContext());
10973 Handle<String> name(String::cast(context->extension()));
10974 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10975 Handle<JSObject> catch_scope =
10976 isolate->factory()->NewJSObject(isolate->object_function());
10977 RETURN_IF_EMPTY_HANDLE_VALUE(
10978 isolate,
10979 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10980 Handle<JSObject>());
10981 return catch_scope;
10982}
10983
10984
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010985// Create a plain JSObject which materializes the block scope for the specified
10986// block context.
10987static Handle<JSObject> MaterializeBlockScope(
10988 Isolate* isolate,
10989 Handle<Context> context) {
10990 ASSERT(context->IsBlockContext());
10991 Handle<SerializedScopeInfo> serialized_scope_info(
10992 SerializedScopeInfo::cast(context->extension()));
10993 ScopeInfo<> scope_info(*serialized_scope_info);
10994
10995 // Allocate and initialize a JSObject with all the arguments, stack locals
10996 // heap locals and extension properties of the debugged function.
10997 Handle<JSObject> block_scope =
10998 isolate->factory()->NewJSObject(isolate->object_function());
10999
11000 // Fill all context locals.
11001 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
11002 if (!CopyContextLocalsToScopeObject(isolate,
11003 serialized_scope_info, scope_info,
11004 context, block_scope)) {
11005 return Handle<JSObject>();
11006 }
11007 }
11008
11009 return block_scope;
11010}
11011
11012
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011013// Iterate over the actual scopes visible from a stack frame. All scopes are
11014// backed by an actual context except the local scope, which is inserted
11015// "artifically" in the context chain.
11016class ScopeIterator {
11017 public:
11018 enum ScopeType {
11019 ScopeTypeGlobal = 0,
11020 ScopeTypeLocal,
11021 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011022 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011023 ScopeTypeCatch,
11024 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011025 };
11026
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011027 ScopeIterator(Isolate* isolate,
11028 JavaScriptFrame* frame,
11029 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011030 : isolate_(isolate),
11031 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011032 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011033 function_(JSFunction::cast(frame->function())),
11034 context_(Context::cast(frame->context())),
11035 local_done_(false),
11036 at_local_(false) {
11037
11038 // Check whether the first scope is actually a local scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011039 // If there is a stack slot for .result then this local scope has been
11040 // created for evaluating top level code and it is not a real local scope.
11041 // Checking for the existence of .result seems fragile, but the scope info
11042 // saved with the code object does not otherwise have that information.
11043 int index = function_->shared()->scope_info()->
11044 StackSlotIndex(isolate_->heap()->result_symbol());
11045 if (index >= 0) {
11046 local_done_ = true;
11047 } else if (context_->IsGlobalContext() ||
11048 context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011049 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011050 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011051 // The context_ is a block or with or catch block from the outer function.
11052 ASSERT(context_->IsWithContext() ||
11053 context_->IsCatchContext() ||
11054 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000011055 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011056 }
11057 }
11058
11059 // More scopes?
11060 bool Done() { return context_.is_null(); }
11061
11062 // Move to the next scope.
11063 void Next() {
11064 // If at a local scope mark the local scope as passed.
11065 if (at_local_) {
11066 at_local_ = false;
11067 local_done_ = true;
11068
11069 // If the current context is not associated with the local scope the
11070 // current context is the next real scope, so don't move to the next
11071 // context in this case.
11072 if (context_->closure() != *function_) {
11073 return;
11074 }
11075 }
11076
11077 // The global scope is always the last in the chain.
11078 if (context_->IsGlobalContext()) {
11079 context_ = Handle<Context>();
11080 return;
11081 }
11082
11083 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011084 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011085
11086 // If passing the local scope indicate that the current scope is now the
11087 // local scope.
11088 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011089 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011090 at_local_ = true;
11091 }
11092 }
11093
11094 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011095 ScopeType Type() {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011096 if (at_local_) {
11097 return ScopeTypeLocal;
11098 }
11099 if (context_->IsGlobalContext()) {
11100 ASSERT(context_->global()->IsGlobalObject());
11101 return ScopeTypeGlobal;
11102 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011103 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011104 return ScopeTypeClosure;
11105 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011106 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011107 return ScopeTypeCatch;
11108 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011109 if (context_->IsBlockContext()) {
11110 return ScopeTypeBlock;
11111 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011112 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011113 return ScopeTypeWith;
11114 }
11115
11116 // Return the JavaScript object with the content of the current scope.
11117 Handle<JSObject> ScopeObject() {
11118 switch (Type()) {
11119 case ScopeIterator::ScopeTypeGlobal:
11120 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011121 case ScopeIterator::ScopeTypeLocal:
11122 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011123 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124 case ScopeIterator::ScopeTypeWith:
11125 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011126 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11127 case ScopeIterator::ScopeTypeCatch:
11128 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011129 case ScopeIterator::ScopeTypeClosure:
11130 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011131 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011132 case ScopeIterator::ScopeTypeBlock:
11133 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011134 }
11135 UNREACHABLE();
11136 return Handle<JSObject>();
11137 }
11138
11139 // Return the context for this scope. For the local context there might not
11140 // be an actual context.
11141 Handle<Context> CurrentContext() {
11142 if (at_local_ && context_->closure() != *function_) {
11143 return Handle<Context>();
11144 }
11145 return context_;
11146 }
11147
11148#ifdef DEBUG
11149 // Debug print of the content of the current scope.
11150 void DebugPrint() {
11151 switch (Type()) {
11152 case ScopeIterator::ScopeTypeGlobal:
11153 PrintF("Global:\n");
11154 CurrentContext()->Print();
11155 break;
11156
11157 case ScopeIterator::ScopeTypeLocal: {
11158 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011159 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011160 scope_info.Print();
11161 if (!CurrentContext().is_null()) {
11162 CurrentContext()->Print();
11163 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011164 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011165 if (extension->IsJSContextExtensionObject()) {
11166 extension->Print();
11167 }
11168 }
11169 }
11170 break;
11171 }
11172
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011173 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011174 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011175 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011176 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011177
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011178 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011179 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011180 CurrentContext()->extension()->Print();
11181 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011182 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011183
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011184 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011185 PrintF("Closure:\n");
11186 CurrentContext()->Print();
11187 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011188 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011189 if (extension->IsJSContextExtensionObject()) {
11190 extension->Print();
11191 }
11192 }
11193 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011194
11195 default:
11196 UNREACHABLE();
11197 }
11198 PrintF("\n");
11199 }
11200#endif
11201
11202 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011203 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011204 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011205 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011206 Handle<JSFunction> function_;
11207 Handle<Context> context_;
11208 bool local_done_;
11209 bool at_local_;
11210
11211 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11212};
11213
11214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011215RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011216 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011217 ASSERT(args.length() == 2);
11218
11219 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011220 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011221 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11222 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011223 if (!maybe_check->ToObject(&check)) return maybe_check;
11224 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011225 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11226
11227 // Get the frame where the debugging is performed.
11228 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011229 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011230 JavaScriptFrame* frame = it.frame();
11231
11232 // Count the visible scopes.
11233 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011234 for (ScopeIterator it(isolate, frame, 0);
11235 !it.Done();
11236 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011237 n++;
11238 }
11239
11240 return Smi::FromInt(n);
11241}
11242
11243
11244static const int kScopeDetailsTypeIndex = 0;
11245static const int kScopeDetailsObjectIndex = 1;
11246static const int kScopeDetailsSize = 2;
11247
11248// Return an array with scope details
11249// args[0]: number: break id
11250// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011251// args[2]: number: inlined frame index
11252// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011253//
11254// The array returned contains the following information:
11255// 0: Scope type
11256// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011257RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011258 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011259 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011260
11261 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011262 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011263 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11264 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011265 if (!maybe_check->ToObject(&check)) return maybe_check;
11266 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011267 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011268 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11269 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011270
11271 // Get the frame where the debugging is performed.
11272 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011273 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011274 JavaScriptFrame* frame = frame_it.frame();
11275
11276 // Find the requested scope.
11277 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011278 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011279 for (; !it.Done() && n < index; it.Next()) {
11280 n++;
11281 }
11282 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011283 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011284 }
11285
11286 // Calculate the size of the result.
11287 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011288 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011289
11290 // Fill in scope details.
11291 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011292 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011293 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011294 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011295
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011296 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011297}
11298
11299
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011300RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011301 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011302 ASSERT(args.length() == 0);
11303
11304#ifdef DEBUG
11305 // Print the scopes for the top frame.
11306 StackFrameLocator locator;
11307 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011308 for (ScopeIterator it(isolate, frame, 0);
11309 !it.Done();
11310 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011311 it.DebugPrint();
11312 }
11313#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011314 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011315}
11316
11317
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011318RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011319 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011320 ASSERT(args.length() == 1);
11321
11322 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011323 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011324 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11325 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011326 if (!maybe_result->ToObject(&result)) return maybe_result;
11327 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011328
11329 // Count all archived V8 threads.
11330 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011331 for (ThreadState* thread =
11332 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011333 thread != NULL;
11334 thread = thread->Next()) {
11335 n++;
11336 }
11337
11338 // Total number of threads is current thread and archived threads.
11339 return Smi::FromInt(n + 1);
11340}
11341
11342
11343static const int kThreadDetailsCurrentThreadIndex = 0;
11344static const int kThreadDetailsThreadIdIndex = 1;
11345static const int kThreadDetailsSize = 2;
11346
11347// Return an array with thread details
11348// args[0]: number: break id
11349// args[1]: number: thread index
11350//
11351// The array returned contains the following information:
11352// 0: Is current thread?
11353// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011354RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011355 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011356 ASSERT(args.length() == 2);
11357
11358 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011359 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011360 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11361 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011362 if (!maybe_check->ToObject(&check)) return maybe_check;
11363 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011364 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11365
11366 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011367 Handle<FixedArray> details =
11368 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011369
11370 // Thread index 0 is current thread.
11371 if (index == 0) {
11372 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011373 details->set(kThreadDetailsCurrentThreadIndex,
11374 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011375 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011376 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011377 } else {
11378 // Find the thread with the requested index.
11379 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011380 ThreadState* thread =
11381 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011382 while (index != n && thread != NULL) {
11383 thread = thread->Next();
11384 n++;
11385 }
11386 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011387 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011388 }
11389
11390 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011391 details->set(kThreadDetailsCurrentThreadIndex,
11392 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011393 details->set(kThreadDetailsThreadIdIndex,
11394 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011395 }
11396
11397 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011398 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011399}
11400
11401
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011402// Sets the disable break state
11403// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011404RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011405 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011406 ASSERT(args.length() == 1);
11407 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011408 isolate->debug()->set_disable_break(disable_break);
11409 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011410}
11411
11412
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011413RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011414 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011415 ASSERT(args.length() == 1);
11416
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011417 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11418 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011419 // Find the number of break points
11420 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011421 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011422 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011423 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011424 Handle<FixedArray>::cast(break_locations));
11425}
11426
11427
11428// Set a break point in a function
11429// args[0]: function
11430// args[1]: number: break source position (within the function source)
11431// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011432RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011433 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011434 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011435 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11436 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011437 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11438 RUNTIME_ASSERT(source_position >= 0);
11439 Handle<Object> break_point_object_arg = args.at<Object>(2);
11440
11441 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011442 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11443 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011444
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011445 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011446}
11447
11448
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011449Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11450 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011451 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011452 // Iterate the heap looking for SharedFunctionInfo generated from the
11453 // script. The inner most SharedFunctionInfo containing the source position
11454 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011455 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011456 // which is found is not compiled it is compiled and the heap is iterated
11457 // again as the compilation might create inner functions from the newly
11458 // compiled function and the actual requested break point might be in one of
11459 // these functions.
11460 bool done = false;
11461 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011462 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011463 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011464 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011465 { // Extra scope for iterator and no-allocation.
11466 isolate->heap()->EnsureHeapIsIterable();
11467 AssertNoAllocation no_alloc_during_heap_iteration;
11468 HeapIterator iterator;
11469 for (HeapObject* obj = iterator.next();
11470 obj != NULL; obj = iterator.next()) {
11471 if (obj->IsSharedFunctionInfo()) {
11472 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11473 if (shared->script() == *script) {
11474 // If the SharedFunctionInfo found has the requested script data and
11475 // contains the source position it is a candidate.
11476 int start_position = shared->function_token_position();
11477 if (start_position == RelocInfo::kNoPosition) {
11478 start_position = shared->start_position();
11479 }
11480 if (start_position <= position &&
11481 position <= shared->end_position()) {
11482 // If there is no candidate or this function is within the current
11483 // candidate this is the new candidate.
11484 if (target.is_null()) {
11485 target_start_position = start_position;
11486 target = shared;
11487 } else {
11488 if (target_start_position == start_position &&
11489 shared->end_position() == target->end_position()) {
11490 // If a top-level function contain only one function
11491 // declartion the source for the top-level and the
11492 // function is the same. In that case prefer the non
11493 // top-level function.
11494 if (!shared->is_toplevel()) {
11495 target_start_position = start_position;
11496 target = shared;
11497 }
11498 } else if (target_start_position <= start_position &&
11499 shared->end_position() <= target->end_position()) {
11500 // This containment check includes equality as a function
11501 // inside a top-level function can share either start or end
11502 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011503 target_start_position = start_position;
11504 target = shared;
11505 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011506 }
11507 }
11508 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011509 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011510 } // End for loop.
11511 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011512
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011513 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011514 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011515 }
11516
11517 // If the candidate found is compiled we are done. NOTE: when lazy
11518 // compilation of inner functions is introduced some additional checking
11519 // needs to be done here to compile inner functions.
11520 done = target->is_compiled();
11521 if (!done) {
11522 // If the candidate is not compiled compile it to reveal any inner
11523 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011524 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011525 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011526 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011527
11528 return *target;
11529}
11530
11531
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011532// Changes the state of a break point in a script and returns source position
11533// where break point was set. NOTE: Regarding performance see the NOTE for
11534// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011535// args[0]: script to set break point in
11536// args[1]: number: break source position (within the script source)
11537// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011538RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011539 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540 ASSERT(args.length() == 3);
11541 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11542 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11543 RUNTIME_ASSERT(source_position >= 0);
11544 Handle<Object> break_point_object_arg = args.at<Object>(2);
11545
11546 // Get the script from the script wrapper.
11547 RUNTIME_ASSERT(wrapper->value()->IsScript());
11548 Handle<Script> script(Script::cast(wrapper->value()));
11549
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011550 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011551 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011552 if (!result->IsUndefined()) {
11553 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11554 // Find position within function. The script position might be before the
11555 // source position of the first function.
11556 int position;
11557 if (shared->start_position() > source_position) {
11558 position = 0;
11559 } else {
11560 position = source_position - shared->start_position();
11561 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011563 position += shared->start_position();
11564 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011566 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011567}
11568
11569
11570// Clear a break point
11571// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011572RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011573 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011574 ASSERT(args.length() == 1);
11575 Handle<Object> break_point_object_arg = args.at<Object>(0);
11576
11577 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011578 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011579
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011581}
11582
11583
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011584// Change the state of break on exceptions.
11585// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11586// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011587RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011588 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011589 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011590 RUNTIME_ASSERT(args[0]->IsNumber());
11591 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011592
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011593 // If the number doesn't match an enum value, the ChangeBreakOnException
11594 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011595 ExceptionBreakType type =
11596 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011597 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011598 isolate->debug()->ChangeBreakOnException(type, enable);
11599 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011600}
11601
11602
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011603// Returns the state of break on exceptions
11604// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011605RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011606 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011607 ASSERT(args.length() == 1);
11608 RUNTIME_ASSERT(args[0]->IsNumber());
11609
11610 ExceptionBreakType type =
11611 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011612 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011613 return Smi::FromInt(result);
11614}
11615
11616
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011617// Prepare for stepping
11618// args[0]: break id for checking execution state
11619// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011620// args[2]: number of times to perform the step, for step out it is the number
11621// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011622RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011623 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011624 ASSERT(args.length() == 3);
11625 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011626 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011627 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11628 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011629 if (!maybe_check->ToObject(&check)) return maybe_check;
11630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011631 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011632 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011633 }
11634
11635 // Get the step action and check validity.
11636 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11637 if (step_action != StepIn &&
11638 step_action != StepNext &&
11639 step_action != StepOut &&
11640 step_action != StepInMin &&
11641 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011642 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011643 }
11644
11645 // Get the number of steps.
11646 int step_count = NumberToInt32(args[2]);
11647 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011648 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011649 }
11650
ager@chromium.orga1645e22009-09-09 19:27:10 +000011651 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011652 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011653
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011654 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011655 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11656 step_count);
11657 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011658}
11659
11660
11661// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011662RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011663 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011664 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011665 isolate->debug()->ClearStepping();
11666 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011667}
11668
11669
11670// Creates a copy of the with context chain. The copy of the context chain is
11671// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011672static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011673 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011674 Handle<Context> current,
11675 Handle<Context> base) {
11676 // At the end of the chain. Return the base context to link to.
11677 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11678 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011679 }
11680
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011681 // Recursively copy the with and catch contexts.
11682 HandleScope scope(isolate);
11683 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011684 Handle<Context> new_previous =
11685 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011686 Handle<Context> new_current;
11687 if (current->IsCatchContext()) {
11688 Handle<String> name(String::cast(current->extension()));
11689 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11690 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011691 isolate->factory()->NewCatchContext(function,
11692 new_previous,
11693 name,
11694 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011695 } else if (current->IsBlockContext()) {
11696 Handle<SerializedScopeInfo> scope_info(
11697 SerializedScopeInfo::cast(current->extension()));
11698 new_current =
11699 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011700 // Copy context slots.
11701 int num_context_slots = scope_info->NumberOfContextSlots();
11702 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11703 new_current->set(i, current->get(i));
11704 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011705 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011706 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011707 Handle<JSObject> extension(JSObject::cast(current->extension()));
11708 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011709 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011710 }
11711 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011712}
11713
11714
11715// Helper function to find or create the arguments object for
11716// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011717static Handle<Object> GetArgumentsObject(Isolate* isolate,
11718 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011719 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011720 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011721 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011722 const ScopeInfo<>* sinfo,
11723 Handle<Context> function_context) {
11724 // Try to find the value of 'arguments' to pass as parameter. If it is not
11725 // found (that is the debugged function does not reference 'arguments' and
11726 // does not support eval) then create an 'arguments' object.
11727 int index;
11728 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011730 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011731 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011732 }
11733 }
11734
11735 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011736 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11737 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011738 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011739 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011740 }
11741 }
11742
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011743 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11744
11745 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011746 Handle<JSObject> arguments =
11747 isolate->factory()->NewArgumentsObject(function, length);
11748 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011749
11750 AssertNoAllocation no_gc;
11751 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011752 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011753 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011754 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011755 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011756 return arguments;
11757}
11758
11759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011760static const char kSourceStr[] =
11761 "(function(arguments,__source__){return eval(__source__);})";
11762
11763
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011765// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011766// extension part has all the parameters and locals of the function on the
11767// stack frame. A function which calls eval with the code to evaluate is then
11768// compiled in this context and called in this context. As this context
11769// replaces the context of the function on the stack frame a new (empty)
11770// function is created as well to be used as the closure for the context.
11771// This function and the context acts as replacements for the function on the
11772// stack frame presenting the same view of the values of parameters and
11773// local variables as if the piece of JavaScript was evaluated at the point
11774// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011775RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011776 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011777
11778 // Check the execution state and decode arguments frame and source to be
11779 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011780 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011781 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011782 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11783 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011784 if (!maybe_check_result->ToObject(&check_result)) {
11785 return maybe_check_result;
11786 }
11787 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011788 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011789 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11790 CONVERT_ARG_CHECKED(String, source, 3);
11791 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11792 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011793
11794 // Handle the processing of break.
11795 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011796
11797 // Get the frame where the debugging is performed.
11798 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011799 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011800 JavaScriptFrame* frame = it.frame();
11801 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011802 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011803 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011804
11805 // Traverse the saved contexts chain to find the active context for the
11806 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011807 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011808 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011809 save = save->prev();
11810 }
11811 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011812 SaveContext savex(isolate);
11813 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011814
11815 // Create the (empty) function replacing the function on the stack frame for
11816 // the purpose of evaluating in the context created below. It is important
11817 // that this function does not describe any parameters and local variables
11818 // in the context. If it does then this will cause problems with the lookup
11819 // in Context::Lookup, where context slots for parameters and local variables
11820 // are looked at before the extension object.
11821 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011822 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11823 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011824 go_between->set_context(function->context());
11825#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011826 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11828 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11829#endif
11830
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011831 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011832 Handle<JSObject> local_scope = MaterializeLocalScope(
11833 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011834 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011835
11836 // Allocate a new context for the debug evaluation and set the extension
11837 // object build.
11838 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011839 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11840 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011841 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011842 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011843 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011844 Handle<Context> function_context;
11845 // Get the function's context if it has one.
11846 if (scope_info->HasHeapAllocatedLocals()) {
11847 function_context = Handle<Context>(frame_context->declaration_context());
11848 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011849 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011851 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011852 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011853 context =
11854 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011855 }
11856
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011857 // Wrap the evaluation statement in a new function compiled in the newly
11858 // created context. The function has one parameter which has to be called
11859 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011860 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011861 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011862
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011863 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 isolate->factory()->NewStringFromAscii(
11865 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011866
11867 // Currently, the eval code will be executed in non-strict mode,
11868 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011869 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011870 Compiler::CompileEval(function_source,
11871 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011872 context->IsGlobalContext(),
11873 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011874 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011875 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011876 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877
11878 // Invoke the result of the compilation to get the evaluation function.
11879 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881 Handle<Object> evaluation_function =
11882 Execution::Call(compiled_function, receiver, 0, NULL,
11883 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011884 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011885
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011886 Handle<Object> arguments = GetArgumentsObject(isolate,
11887 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011888 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011889 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890
11891 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011892 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000011894 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
11895 receiver,
11896 ARRAY_SIZE(argv),
11897 argv,
11898 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011899 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011900
11901 // Skip the global proxy as it has no properties and always delegates to the
11902 // real global object.
11903 if (result->IsJSGlobalProxy()) {
11904 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11905 }
11906
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011907 return *result;
11908}
11909
11910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011911RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011912 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011913
11914 // Check the execution state and decode arguments frame and source to be
11915 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011916 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011917 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011918 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11919 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011920 if (!maybe_check_result->ToObject(&check_result)) {
11921 return maybe_check_result;
11922 }
11923 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011924 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011925 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011926 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011927
11928 // Handle the processing of break.
11929 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011930
11931 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011932 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011934 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011935 top = top->prev();
11936 }
11937 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011938 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011939 }
11940
11941 // Get the global context now set to the top context from before the
11942 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011943 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011944
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011945 bool is_global = true;
11946
11947 if (additional_context->IsJSObject()) {
11948 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011949 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11950 isolate->factory()->empty_string(),
11951 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011952 go_between->set_context(*context);
11953 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011954 isolate->factory()->NewFunctionContext(
11955 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011956 context->set_extension(JSObject::cast(*additional_context));
11957 is_global = false;
11958 }
11959
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011960 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011961 // Currently, the eval code will be executed in non-strict mode,
11962 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011963 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011964 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011965 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011966 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011967 Handle<JSFunction>(
11968 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11969 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970
11971 // Invoke the result of the compilation to get the evaluation function.
11972 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011973 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011974 Handle<Object> result =
11975 Execution::Call(compiled_function, receiver, 0, NULL,
11976 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011977 // Clear the oneshot breakpoints so that the debugger does not step further.
11978 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011979 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011980 return *result;
11981}
11982
11983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011984RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011985 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011986 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011987
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011989 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011990
11991 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011992 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011993 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11994 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11995 // because using
11996 // instances->set(i, *GetScriptWrapper(script))
11997 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11998 // already have deferenced the instances handle.
11999 Handle<JSValue> wrapper = GetScriptWrapper(script);
12000 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012001 }
12002
12003 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012004 Handle<JSObject> result =
12005 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012006 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012007 return *result;
12008}
12009
12010
12011// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012012static int DebugReferencedBy(HeapIterator* iterator,
12013 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012014 Object* instance_filter, int max_references,
12015 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012016 JSFunction* arguments_function) {
12017 NoHandleAllocation ha;
12018 AssertNoAllocation no_alloc;
12019
12020 // Iterate the heap.
12021 int count = 0;
12022 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012023 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012024 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012025 (max_references == 0 || count < max_references)) {
12026 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012027 if (heap_obj->IsJSObject()) {
12028 // Skip context extension objects and argument arrays as these are
12029 // checked in the context of functions using them.
12030 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012031 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012032 obj->map()->constructor() == arguments_function) {
12033 continue;
12034 }
12035
12036 // Check if the JS object has a reference to the object looked for.
12037 if (obj->ReferencesObject(target)) {
12038 // Check instance filter if supplied. This is normally used to avoid
12039 // references from mirror objects (see Runtime_IsInPrototypeChain).
12040 if (!instance_filter->IsUndefined()) {
12041 Object* V = obj;
12042 while (true) {
12043 Object* prototype = V->GetPrototype();
12044 if (prototype->IsNull()) {
12045 break;
12046 }
12047 if (instance_filter == prototype) {
12048 obj = NULL; // Don't add this object.
12049 break;
12050 }
12051 V = prototype;
12052 }
12053 }
12054
12055 if (obj != NULL) {
12056 // Valid reference found add to instance array if supplied an update
12057 // count.
12058 if (instances != NULL && count < instances_size) {
12059 instances->set(count, obj);
12060 }
12061 last = obj;
12062 count++;
12063 }
12064 }
12065 }
12066 }
12067
12068 // Check for circular reference only. This can happen when the object is only
12069 // referenced from mirrors and has a circular reference in which case the
12070 // object is not really alive and would have been garbage collected if not
12071 // referenced from the mirror.
12072 if (count == 1 && last == target) {
12073 count = 0;
12074 }
12075
12076 // Return the number of referencing objects found.
12077 return count;
12078}
12079
12080
12081// Scan the heap for objects with direct references to an object
12082// args[0]: the object to find references to
12083// args[1]: constructor function for instances to exclude (Mirror)
12084// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012085RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012086 ASSERT(args.length() == 3);
12087
12088 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012089 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12090 // The heap iterator reserves the right to do a GC to make the heap iterable.
12091 // Due to the GC above we know it won't need to do that, but it seems cleaner
12092 // to get the heap iterator constructed before we start having unprotected
12093 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012094
12095 // Check parameters.
12096 CONVERT_CHECKED(JSObject, target, args[0]);
12097 Object* instance_filter = args[1];
12098 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12099 instance_filter->IsJSObject());
12100 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12101 RUNTIME_ASSERT(max_references >= 0);
12102
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012103
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012104 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012105 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012106 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012107 JSFunction* arguments_function =
12108 JSFunction::cast(arguments_boilerplate->map()->constructor());
12109
12110 // Get the number of referencing objects.
12111 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012112 HeapIterator heap_iterator;
12113 count = DebugReferencedBy(&heap_iterator,
12114 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012115 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012116
12117 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012118 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012119 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012120 if (!maybe_object->ToObject(&object)) return maybe_object;
12121 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122 FixedArray* instances = FixedArray::cast(object);
12123
12124 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012125 // AllocateFixedArray above does not make the heap non-iterable.
12126 ASSERT(HEAP->IsHeapIterable());
12127 HeapIterator heap_iterator2;
12128 count = DebugReferencedBy(&heap_iterator2,
12129 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012130 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012131
12132 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012133 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012134 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012135 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012136 if (!maybe_result->ToObject(&result)) return maybe_result;
12137 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012138}
12139
12140
12141// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012142static int DebugConstructedBy(HeapIterator* iterator,
12143 JSFunction* constructor,
12144 int max_references,
12145 FixedArray* instances,
12146 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012147 AssertNoAllocation no_alloc;
12148
12149 // Iterate the heap.
12150 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012151 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012152 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012153 (max_references == 0 || count < max_references)) {
12154 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012155 if (heap_obj->IsJSObject()) {
12156 JSObject* obj = JSObject::cast(heap_obj);
12157 if (obj->map()->constructor() == constructor) {
12158 // Valid reference found add to instance array if supplied an update
12159 // count.
12160 if (instances != NULL && count < instances_size) {
12161 instances->set(count, obj);
12162 }
12163 count++;
12164 }
12165 }
12166 }
12167
12168 // Return the number of referencing objects found.
12169 return count;
12170}
12171
12172
12173// Scan the heap for objects constructed by a specific function.
12174// args[0]: the constructor to find instances of
12175// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012176RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177 ASSERT(args.length() == 2);
12178
12179 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012180 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012181
12182 // Check parameters.
12183 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12184 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12185 RUNTIME_ASSERT(max_references >= 0);
12186
12187 // Get the number of referencing objects.
12188 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012189 HeapIterator heap_iterator;
12190 count = DebugConstructedBy(&heap_iterator,
12191 constructor,
12192 max_references,
12193 NULL,
12194 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012195
12196 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012197 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012198 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012199 if (!maybe_object->ToObject(&object)) return maybe_object;
12200 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012201 FixedArray* instances = FixedArray::cast(object);
12202
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012203 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012204 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012205 HeapIterator heap_iterator2;
12206 count = DebugConstructedBy(&heap_iterator2,
12207 constructor,
12208 max_references,
12209 instances,
12210 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012211
12212 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012213 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012214 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12215 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012216 if (!maybe_result->ToObject(&result)) return maybe_result;
12217 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012218 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012219}
12220
12221
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012222// Find the effective prototype object as returned by __proto__.
12223// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012224RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012225 ASSERT(args.length() == 1);
12226
12227 CONVERT_CHECKED(JSObject, obj, args[0]);
12228
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012229 // Use the __proto__ accessor.
12230 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012231}
12232
12233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012234RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012235 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012236 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012237 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012238}
12239
12240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012241RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012242#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012243 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012244 ASSERT(args.length() == 1);
12245 // Get the function and make sure it is compiled.
12246 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012247 Handle<SharedFunctionInfo> shared(func->shared());
12248 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012249 return Failure::Exception();
12250 }
12251 func->code()->PrintLn();
12252#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012253 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012254}
ager@chromium.org9085a012009-05-11 19:22:57 +000012255
12256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012257RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012258#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012259 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012260 ASSERT(args.length() == 1);
12261 // Get the function and make sure it is compiled.
12262 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012263 Handle<SharedFunctionInfo> shared(func->shared());
12264 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012265 return Failure::Exception();
12266 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012267 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012268#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012269 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012270}
12271
12272
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012273RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012274 NoHandleAllocation ha;
12275 ASSERT(args.length() == 1);
12276
12277 CONVERT_CHECKED(JSFunction, f, args[0]);
12278 return f->shared()->inferred_name();
12279}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012280
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012281
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012282static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12283 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012284 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012285 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012286 int counter = 0;
12287 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012288 for (HeapObject* obj = iterator->next();
12289 obj != NULL;
12290 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012291 ASSERT(obj != NULL);
12292 if (!obj->IsSharedFunctionInfo()) {
12293 continue;
12294 }
12295 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12296 if (shared->script() != script) {
12297 continue;
12298 }
12299 if (counter < buffer_size) {
12300 buffer->set(counter, shared);
12301 }
12302 counter++;
12303 }
12304 return counter;
12305}
12306
12307// For a script finds all SharedFunctionInfo's in the heap that points
12308// to this script. Returns JSArray of SharedFunctionInfo wrapped
12309// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012310RUNTIME_FUNCTION(MaybeObject*,
12311 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012312 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012313 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012314 CONVERT_CHECKED(JSValue, script_value, args[0]);
12315
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012316
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012317 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12318
12319 const int kBufferSize = 32;
12320
12321 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012322 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012323 int number;
12324 {
12325 isolate->heap()->EnsureHeapIsIterable();
12326 AssertNoAllocation no_allocations;
12327 HeapIterator heap_iterator;
12328 Script* scr = *script;
12329 FixedArray* arr = *array;
12330 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12331 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012332 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012333 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012334 isolate->heap()->EnsureHeapIsIterable();
12335 AssertNoAllocation no_allocations;
12336 HeapIterator heap_iterator;
12337 Script* scr = *script;
12338 FixedArray* arr = *array;
12339 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012340 }
12341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012342 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012343 result->set_length(Smi::FromInt(number));
12344
12345 LiveEdit::WrapSharedFunctionInfos(result);
12346
12347 return *result;
12348}
12349
12350// For a script calculates compilation information about all its functions.
12351// The script source is explicitly specified by the second argument.
12352// The source of the actual script is not used, however it is important that
12353// all generated code keeps references to this particular instance of script.
12354// Returns a JSArray of compilation infos. The array is ordered so that
12355// each function with all its descendant is always stored in a continues range
12356// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012357RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012358 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012359 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012360 CONVERT_CHECKED(JSValue, script, args[0]);
12361 CONVERT_ARG_CHECKED(String, source, 1);
12362 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12363
12364 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12365
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012366 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012367 return Failure::Exception();
12368 }
12369
12370 return result;
12371}
12372
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012373// Changes the source of the script to a new_source.
12374// If old_script_name is provided (i.e. is a String), also creates a copy of
12375// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012376RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012377 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012378 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012379 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12380 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012381 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012382
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012383 CONVERT_CHECKED(Script, original_script_pointer,
12384 original_script_value->value());
12385 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012386
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012387 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12388 new_source,
12389 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012390
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012391 if (old_script->IsScript()) {
12392 Handle<Script> script_handle(Script::cast(old_script));
12393 return *(GetScriptWrapper(script_handle));
12394 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012395 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012396 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012397}
12398
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012400RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012401 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012402 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012403 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12404 return LiveEdit::FunctionSourceUpdated(shared_info);
12405}
12406
12407
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012408// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012409RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012410 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012411 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012412 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12413 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12414
ager@chromium.orgac091b72010-05-05 07:34:42 +000012415 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012416}
12417
12418// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012419RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012420 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012421 HandleScope scope(isolate);
12422 Handle<Object> function_object(args[0], isolate);
12423 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012424
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012425 if (function_object->IsJSValue()) {
12426 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12427 if (script_object->IsJSValue()) {
12428 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012429 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012430 }
12431
12432 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12433 } else {
12434 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12435 // and we check it in this function.
12436 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012437
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012438 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012439}
12440
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012441
12442// In a code of a parent function replaces original function as embedded object
12443// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012444RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012445 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012446 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012447
12448 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12449 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12450 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12451
12452 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12453 subst_wrapper);
12454
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012455 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012456}
12457
12458
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012459// Updates positions of a shared function info (first parameter) according
12460// to script source change. Text change is described in second parameter as
12461// array of groups of 3 numbers:
12462// (change_begin, change_end, change_end_new_position).
12463// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012464RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012465 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012466 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012467 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12468 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12469
ager@chromium.orgac091b72010-05-05 07:34:42 +000012470 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012471}
12472
12473
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012474// For array of SharedFunctionInfo's (each wrapped in JSValue)
12475// checks that none of them have activations on stacks (of any thread).
12476// Returns array of the same length with corresponding results of
12477// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012478RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012479 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012481 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012482 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012483
ager@chromium.org357bf652010-04-12 11:30:10 +000012484 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012485}
12486
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012487// Compares 2 strings line-by-line, then token-wise and returns diff in form
12488// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12489// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012490RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012491 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012492 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012493 CONVERT_ARG_CHECKED(String, s1, 0);
12494 CONVERT_ARG_CHECKED(String, s2, 1);
12495
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012496 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012497}
12498
12499
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012500// A testing entry. Returns statement position which is the closest to
12501// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012502RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012503 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012504 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012505 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12506 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12507
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012508 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012509
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012510 if (code->kind() != Code::FUNCTION &&
12511 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012512 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012513 }
12514
12515 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012516 int closest_pc = 0;
12517 int distance = kMaxInt;
12518 while (!it.done()) {
12519 int statement_position = static_cast<int>(it.rinfo()->data());
12520 // Check if this break point is closer that what was previously found.
12521 if (source_position <= statement_position &&
12522 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012523 closest_pc =
12524 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012525 distance = statement_position - source_position;
12526 // Check whether we can't get any closer.
12527 if (distance == 0) break;
12528 }
12529 it.next();
12530 }
12531
12532 return Smi::FromInt(closest_pc);
12533}
12534
12535
ager@chromium.org357bf652010-04-12 11:30:10 +000012536// Calls specified function with or without entering the debugger.
12537// This is used in unit tests to run code as if debugger is entered or simply
12538// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012539RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012540 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012541 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012542 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12543 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12544
12545 Handle<Object> result;
12546 bool pending_exception;
12547 {
12548 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012549 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012550 &pending_exception);
12551 } else {
12552 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012553 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012554 &pending_exception);
12555 }
12556 }
12557 if (!pending_exception) {
12558 return *result;
12559 } else {
12560 return Failure::Exception();
12561 }
12562}
12563
12564
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012565// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012566RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012567 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012568 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012569 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12570 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012571 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012572}
12573
12574
12575// Performs a GC.
12576// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012577RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012578 isolate->heap()->CollectAllGarbage(true);
12579 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012580}
12581
12582
12583// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012584RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012585 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012586 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012587 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012588 }
12589 return Smi::FromInt(usage);
12590}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012591
12592
12593// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012594RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012595#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012596 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012597#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012598 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012599#endif
12600}
12601
12602
12603// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012604RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012605#ifdef LIVE_OBJECT_LIST
12606 return LiveObjectList::Capture();
12607#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012608 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012609#endif
12610}
12611
12612
12613// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012614RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012615#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012616 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012617 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012618 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012619#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012620 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012621#endif
12622}
12623
12624
12625// Generates the response to a debugger request for a dump of the objects
12626// contained in the difference between the captured live object lists
12627// specified by id1 and id2.
12628// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12629// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012630RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012631#ifdef LIVE_OBJECT_LIST
12632 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012633 CONVERT_SMI_ARG_CHECKED(id1, 0);
12634 CONVERT_SMI_ARG_CHECKED(id2, 1);
12635 CONVERT_SMI_ARG_CHECKED(start, 2);
12636 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012637 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12638 EnterDebugger enter_debugger;
12639 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12640#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012641 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012642#endif
12643}
12644
12645
12646// Gets the specified object as requested by the debugger.
12647// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012648RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012649#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012650 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012651 Object* result = LiveObjectList::GetObj(obj_id);
12652 return result;
12653#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012654 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012655#endif
12656}
12657
12658
12659// Gets the obj id for the specified address if valid.
12660// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012661RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012662#ifdef LIVE_OBJECT_LIST
12663 HandleScope scope;
12664 CONVERT_ARG_CHECKED(String, address, 0);
12665 Object* result = LiveObjectList::GetObjId(address);
12666 return result;
12667#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012668 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012669#endif
12670}
12671
12672
12673// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012674RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012675#ifdef LIVE_OBJECT_LIST
12676 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012677 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012678 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12679 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12680 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12681 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12682 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12683
12684 Handle<JSObject> instance_filter;
12685 if (args[1]->IsJSObject()) {
12686 instance_filter = args.at<JSObject>(1);
12687 }
12688 bool verbose = false;
12689 if (args[2]->IsBoolean()) {
12690 verbose = args[2]->IsTrue();
12691 }
12692 int start = 0;
12693 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012694 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012695 }
12696 int limit = Smi::kMaxValue;
12697 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012698 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012699 }
12700
12701 return LiveObjectList::GetObjRetainers(obj_id,
12702 instance_filter,
12703 verbose,
12704 start,
12705 limit,
12706 filter_obj);
12707#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012708 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012709#endif
12710}
12711
12712
12713// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012714RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012715#ifdef LIVE_OBJECT_LIST
12716 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012717 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12718 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012719 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12720
12721 Handle<JSObject> instance_filter;
12722 if (args[2]->IsJSObject()) {
12723 instance_filter = args.at<JSObject>(2);
12724 }
12725
12726 Object* result =
12727 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12728 return result;
12729#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012730 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012731#endif
12732}
12733
12734
12735// Generates the response to a debugger request for a list of all
12736// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012737RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012738#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012739 CONVERT_SMI_ARG_CHECKED(start, 0);
12740 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012741 return LiveObjectList::Info(start, count);
12742#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012743 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012744#endif
12745}
12746
12747
12748// Gets a dump of the specified object as requested by the debugger.
12749// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012750RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012751#ifdef LIVE_OBJECT_LIST
12752 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012753 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012754 Object* result = LiveObjectList::PrintObj(obj_id);
12755 return result;
12756#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012757 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012758#endif
12759}
12760
12761
12762// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012763RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012764#ifdef LIVE_OBJECT_LIST
12765 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012766 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012767#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012768 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012769#endif
12770}
12771
12772
12773// Generates the response to a debugger request for a summary of the types
12774// of objects in the difference between the captured live object lists
12775// specified by id1 and id2.
12776// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12777// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012778RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012779#ifdef LIVE_OBJECT_LIST
12780 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012781 CONVERT_SMI_ARG_CHECKED(id1, 0);
12782 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012783 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12784
12785 EnterDebugger enter_debugger;
12786 return LiveObjectList::Summarize(id1, id2, filter_obj);
12787#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012788 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012789#endif
12790}
12791
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012792#endif // ENABLE_DEBUGGER_SUPPORT
12793
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012794
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012795RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012796 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012797 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012798 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012799}
12800
12801
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012802RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012803 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012804 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012805 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012806}
12807
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012808
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012809// Finds the script object from the script data. NOTE: This operation uses
12810// heap traversal to find the function generated for the source position
12811// for the requested break point. For lazily compiled functions several heap
12812// traversals might be required rendering this operation as a rather slow
12813// operation. However for setting break points which is normally done through
12814// some kind of user interaction the performance is not crucial.
12815static Handle<Object> Runtime_GetScriptFromScriptName(
12816 Handle<String> script_name) {
12817 // Scan the heap for Script objects to find the script with the requested
12818 // script data.
12819 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012820 script_name->GetHeap()->EnsureHeapIsIterable();
12821 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012822 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012823 HeapObject* obj = NULL;
12824 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012825 // If a script is found check if it has the script data requested.
12826 if (obj->IsScript()) {
12827 if (Script::cast(obj)->name()->IsString()) {
12828 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12829 script = Handle<Script>(Script::cast(obj));
12830 }
12831 }
12832 }
12833 }
12834
12835 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012836 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012837
12838 // Return the script found.
12839 return GetScriptWrapper(script);
12840}
12841
12842
12843// Get the script object from script data. NOTE: Regarding performance
12844// see the NOTE for GetScriptFromScriptData.
12845// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012846RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012847 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012848
12849 ASSERT(args.length() == 1);
12850
12851 CONVERT_CHECKED(String, script_name, args[0]);
12852
12853 // Find the requested script.
12854 Handle<Object> result =
12855 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12856 return *result;
12857}
12858
12859
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012860// Determines whether the given stack frame should be displayed in
12861// a stack trace. The caller is the error constructor that asked
12862// for the stack trace to be collected. The first time a construct
12863// call to this function is encountered it is skipped. The seen_caller
12864// in/out parameter is used to remember if the caller has been seen
12865// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012866static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12867 Object* caller,
12868 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012869 // Only display JS frames.
12870 if (!raw_frame->is_java_script())
12871 return false;
12872 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12873 Object* raw_fun = frame->function();
12874 // Not sure when this can happen but skip it just in case.
12875 if (!raw_fun->IsJSFunction())
12876 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012877 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012878 *seen_caller = true;
12879 return false;
12880 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012881 // Skip all frames until we've seen the caller.
12882 if (!(*seen_caller)) return false;
12883 // Also, skip the most obvious builtin calls. We recognize builtins
12884 // as (1) functions called with the builtins object as the receiver and
12885 // as (2) functions from native scripts called with undefined as the
12886 // receiver (direct calls to helper functions in the builtins
12887 // code). Some builtin calls (such as Number.ADD which is invoked
12888 // using 'call') are very difficult to recognize so we're leaving
12889 // them in for now.
12890 if (frame->receiver()->IsJSBuiltinsObject()) {
12891 return false;
12892 }
12893 JSFunction* fun = JSFunction::cast(raw_fun);
12894 Object* raw_script = fun->shared()->script();
12895 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12896 int script_type = Script::cast(raw_script)->type()->value();
12897 return script_type != Script::TYPE_NATIVE;
12898 }
12899 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012900}
12901
12902
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012903// Collect the raw data for a stack trace. Returns an array of 4
12904// element segments each containing a receiver, function, code and
12905// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012906RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012907 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012908 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012909 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12910
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012911 HandleScope scope(isolate);
12912 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012913
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012914 limit = Max(limit, 0); // Ensure that limit is not negative.
12915 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012916 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012917 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012918
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012919 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012920 // If the caller parameter is a function we skip frames until we're
12921 // under it before starting to collect.
12922 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012923 int cursor = 0;
12924 int frames_seen = 0;
12925 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012926 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012927 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012928 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012929 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012930 // Set initial size to the maximum inlining level + 1 for the outermost
12931 // function.
12932 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012933 frame->Summarize(&frames);
12934 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012935 if (cursor + 4 > elements->length()) {
12936 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12937 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012938 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012939 for (int i = 0; i < cursor; i++) {
12940 new_elements->set(i, elements->get(i));
12941 }
12942 elements = new_elements;
12943 }
12944 ASSERT(cursor + 4 <= elements->length());
12945
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012946 Handle<Object> recv = frames[i].receiver();
12947 Handle<JSFunction> fun = frames[i].function();
12948 Handle<Code> code = frames[i].code();
12949 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012950 elements->set(cursor++, *recv);
12951 elements->set(cursor++, *fun);
12952 elements->set(cursor++, *code);
12953 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012954 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012955 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012956 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012957 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012958 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012959 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012960 return *result;
12961}
12962
12963
ager@chromium.org3811b432009-10-28 14:53:37 +000012964// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012965RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012966 ASSERT_EQ(args.length(), 0);
12967
12968 NoHandleAllocation ha;
12969
12970 const char* version_string = v8::V8::GetVersion();
12971
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012972 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12973 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012974}
12975
12976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012977RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012978 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012979 OS::PrintError("abort: %s\n",
12980 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012981 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012982 OS::Abort();
12983 UNREACHABLE();
12984 return NULL;
12985}
12986
12987
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012988RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012989 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012990 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012991 Object* key = args[1];
12992
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012993 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012994 Object* o = cache->get(finger_index);
12995 if (o == key) {
12996 // The fastest case: hit the same place again.
12997 return cache->get(finger_index + 1);
12998 }
12999
13000 for (int i = finger_index - 2;
13001 i >= JSFunctionResultCache::kEntriesIndex;
13002 i -= 2) {
13003 o = cache->get(i);
13004 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013005 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013006 return cache->get(i + 1);
13007 }
13008 }
13009
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013010 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013011 ASSERT(size <= cache->length());
13012
13013 for (int i = size - 2; i > finger_index; i -= 2) {
13014 o = cache->get(i);
13015 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013016 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013017 return cache->get(i + 1);
13018 }
13019 }
13020
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013021 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013022 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013023
13024 Handle<JSFunctionResultCache> cache_handle(cache);
13025 Handle<Object> key_handle(key);
13026 Handle<Object> value;
13027 {
13028 Handle<JSFunction> factory(JSFunction::cast(
13029 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13030 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013031 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013032 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013033 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013034 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013035 value = Execution::Call(factory,
13036 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013037 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013038 argv,
13039 &pending_exception);
13040 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013041 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013042
13043#ifdef DEBUG
13044 cache_handle->JSFunctionResultCacheVerify();
13045#endif
13046
13047 // Function invocation may have cleared the cache. Reread all the data.
13048 finger_index = cache_handle->finger_index();
13049 size = cache_handle->size();
13050
13051 // If we have spare room, put new data into it, otherwise evict post finger
13052 // entry which is likely to be the least recently used.
13053 int index = -1;
13054 if (size < cache_handle->length()) {
13055 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13056 index = size;
13057 } else {
13058 index = finger_index + JSFunctionResultCache::kEntrySize;
13059 if (index == cache_handle->length()) {
13060 index = JSFunctionResultCache::kEntriesIndex;
13061 }
13062 }
13063
13064 ASSERT(index % 2 == 0);
13065 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13066 ASSERT(index < cache_handle->length());
13067
13068 cache_handle->set(index, *key_handle);
13069 cache_handle->set(index + 1, *value);
13070 cache_handle->set_finger_index(index);
13071
13072#ifdef DEBUG
13073 cache_handle->JSFunctionResultCacheVerify();
13074#endif
13075
13076 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013077}
13078
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013080RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013081 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013082 CONVERT_ARG_CHECKED(String, type, 0);
13083 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013084 return *isolate->factory()->NewJSMessageObject(
13085 type,
13086 arguments,
13087 0,
13088 0,
13089 isolate->factory()->undefined_value(),
13090 isolate->factory()->undefined_value(),
13091 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013092}
13093
13094
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013095RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013096 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13097 return message->type();
13098}
13099
13100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013101RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013102 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13103 return message->arguments();
13104}
13105
13106
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013107RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013108 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13109 return Smi::FromInt(message->start_position());
13110}
13111
13112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013113RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013114 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13115 return message->script();
13116}
13117
13118
kasper.lund44510672008-07-25 07:37:58 +000013119#ifdef DEBUG
13120// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13121// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013122RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013123 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013124 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013125#define COUNT_ENTRY(Name, argc, ressize) + 1
13126 int entry_count = 0
13127 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13128 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13129 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13130#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013131 Factory* factory = isolate->factory();
13132 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013133 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013134 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013135#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013136 { \
13137 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013138 Handle<String> name; \
13139 /* Inline runtime functions have an underscore in front of the name. */ \
13140 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013141 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013142 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13143 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013144 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013145 Vector<const char>(#Name, StrLength(#Name))); \
13146 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013147 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013148 pair_elements->set(0, *name); \
13149 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013150 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013151 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013152 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013153 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013154 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013155 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013156 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013157 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013158#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013159 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013160 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013161 return *result;
13162}
kasper.lund44510672008-07-25 07:37:58 +000013163#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013164
13165
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013166RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013167 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013168 CONVERT_CHECKED(String, format, args[0]);
13169 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013170 String::FlatContent format_content = format->GetFlatContent();
13171 RUNTIME_ASSERT(format_content.IsAscii());
13172 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013173 LOGGER->LogRuntime(chars, elms);
13174 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013175}
13176
13177
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013178RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013179 UNREACHABLE(); // implemented as macro in the parser
13180 return NULL;
13181}
13182
13183
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013184#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13185 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13186 CONVERT_CHECKED(JSObject, obj, args[0]); \
13187 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13188 }
13189
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013190ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013191ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13192ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13193ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13194ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13195ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13196ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13197ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13198ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13199ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13200ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13201ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13202ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13203ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13204
13205#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13206
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013207
13208RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13209 ASSERT(args.length() == 2);
13210 CONVERT_CHECKED(JSObject, obj1, args[0]);
13211 CONVERT_CHECKED(JSObject, obj2, args[1]);
13212 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13213}
13214
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013215// ----------------------------------------------------------------------------
13216// Implementation of Runtime
13217
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013218#define F(name, number_of_args, result_size) \
13219 { Runtime::k##name, Runtime::RUNTIME, #name, \
13220 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013221
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013222
13223#define I(name, number_of_args, result_size) \
13224 { Runtime::kInline##name, Runtime::INLINE, \
13225 "_" #name, NULL, number_of_args, result_size },
13226
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013227static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013228 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013229 INLINE_FUNCTION_LIST(I)
13230 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013231};
13232
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013234MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13235 Object* dictionary) {
13236 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013237 ASSERT(dictionary != NULL);
13238 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13239 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013240 Object* name_symbol;
13241 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013242 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013243 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13244 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013245 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013246 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13247 String::cast(name_symbol),
13248 Smi::FromInt(i),
13249 PropertyDetails(NONE, NORMAL));
13250 if (!maybe_dictionary->ToObject(&dictionary)) {
13251 // Non-recoverable failure. Calling code must restart heap
13252 // initialization.
13253 return maybe_dictionary;
13254 }
13255 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013256 }
13257 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013258}
13259
13260
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013261const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13262 Heap* heap = name->GetHeap();
13263 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013264 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013265 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013266 int function_index = Smi::cast(smi_index)->value();
13267 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013268 }
13269 return NULL;
13270}
13271
13272
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013273const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013274 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13275}
13276
13277
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013278void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013279 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013280 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013281 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013282 if (isolate->heap()->new_space()->AddFreshPage()) {
13283 return;
13284 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013285 // Try to do a garbage collection; ignore it if it fails. The C
13286 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013287 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013288 } else {
13289 // Handle last resort GC and make sure to allow future allocations
13290 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013291 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013292 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013293 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013294}
13295
13296
13297} } // namespace v8::internal